| /* |
| * 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 static com.android.manifmerger.Actions.NodeRecord; |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Mockito.when; |
| |
| import com.android.SdkConstants; |
| import com.android.utils.StdLogger; |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| |
| import junit.framework.TestCase; |
| |
| import org.mockito.Mock; |
| import org.mockito.Mockito; |
| import org.mockito.MockitoAnnotations; |
| import org.xml.sax.SAXException; |
| |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.logging.Logger; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| /** |
| * Tests for the {@link XmlElement} |
| */ |
| public class XmlElementTest extends TestCase { |
| |
| @Mock |
| MergingReport.Builder mergingReport; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| MockitoAnnotations.initMocks(this); |
| } |
| |
| public void testToolsNodeInstructions() |
| throws ParserConfigurationException, SAXException, IOException { |
| String input = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " tools:node=\"remove\"/>\n" |
| + "\n" |
| + " <activity android:name=\"activityTwo\" " |
| + " tools:node=\"removeAll\"/>\n" |
| + "\n" |
| + " <activity android:name=\"activityThree\" " |
| + " tools:node=\"mergeOnlyAttributes\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testToolsNodeInstructions()"), input); |
| Optional<XmlElement> activity = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne"); |
| assertTrue(activity.isPresent()); |
| assertEquals(NodeOperationType.REMOVE, |
| activity.get().getOperationType()); |
| activity = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityTwo"); |
| assertTrue(activity.isPresent()); |
| assertEquals(NodeOperationType.REMOVE_ALL, |
| activity.get().getOperationType()); |
| activity = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityThree"); |
| assertTrue(activity.isPresent()); |
| assertEquals(NodeOperationType.MERGE_ONLY_ATTRIBUTES, |
| activity.get().getOperationType()); |
| } |
| |
| public void testInvalidNodeInstruction() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| String input = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " tools:node=\"funkyValue\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| try { |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation( |
| getClass(), "testInvalidNodeInstruction()"), input); |
| xmlDocument.getRootNode(); |
| fail("Exception not thrown"); |
| } catch (IllegalArgumentException expected) { |
| // expected. |
| } |
| } |
| |
| public void testAttributeInstructions() |
| throws ParserConfigurationException, SAXException, IOException { |
| String input = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " tools:remove=\"android:theme\"/>\n" |
| + "\n" |
| + " <activity android:name=\"activityTwo\" " |
| + " android:theme=\"@theme1\"\n" |
| + " tools:replace=\"android:theme\"/>\n" |
| + "\n" |
| + " <activity android:name=\"activityThree\" " |
| + " tools:strict=\"android:exported\"/>\n" |
| + "\n" |
| + " <activity android:name=\"activityFour\" " |
| + " android:theme=\"@theme1\"\n" |
| + " android:exported=\"true\"\n" |
| + " android:windowSoftInputMode=\"stateUnchanged\"\n" |
| + " tools:replace=" |
| + "\"android:theme, android:exported,android:windowSoftInputMode\"/>\n" |
| + "\n" |
| + " <activity android:name=\"activityFive\" " |
| + " android:theme=\"@theme1\"\n" |
| + " android:exported=\"true\"\n" |
| + " android:windowSoftInputMode=\"stateUnchanged\"\n" |
| + " tools:remove=\"android:exported\"\n" |
| + " tools:replace=\"android:theme\"\n" |
| + " tools:strict=\"android:windowSoftInputMode\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| // ActivityOne, remove operation. |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testAttributeInstructions()"), input); |
| Optional<XmlElement> activityOptional = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne"); |
| assertTrue(activityOptional.isPresent()); |
| XmlElement activity = activityOptional.get(); |
| assertEquals(1, activity.getAttributeOperations().size()); |
| AttributeOperationType attributeOperationType = |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme")); |
| assertEquals(AttributeOperationType.REMOVE, attributeOperationType); |
| |
| // ActivityTwo, replace operation. |
| activityOptional = xmlDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityTwo"); |
| assertTrue(activityOptional.isPresent()); |
| activity = activityOptional.get(); |
| assertEquals(1, activity.getAttributeOperations().size()); |
| attributeOperationType = activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme")); |
| assertEquals(AttributeOperationType.REPLACE, attributeOperationType); |
| |
| // ActivityThree, strict operation. |
| activityOptional = xmlDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityThree"); |
| assertTrue(activityOptional.isPresent()); |
| activity = activityOptional.get(); |
| assertEquals(1, activity.getAttributeOperations().size()); |
| attributeOperationType = activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme")); |
| assertEquals(AttributeOperationType.STRICT, attributeOperationType); |
| |
| // ActivityFour, multiple target fields. |
| activityOptional = xmlDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityFour"); |
| assertTrue(activityOptional.isPresent()); |
| activity = activityOptional.get(); |
| assertEquals(3, activity.getAttributeOperations().size()); |
| assertEquals(AttributeOperationType.REPLACE, |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme"))); |
| assertEquals(AttributeOperationType.REPLACE, |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme"))); |
| assertEquals(AttributeOperationType.REPLACE, |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme"))); |
| |
| // ActivityFive, multiple operations. |
| activityOptional = xmlDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityFive"); |
| assertTrue(activityOptional.isPresent()); |
| activity = activityOptional.get(); |
| assertEquals(3, activity.getAttributeOperations().size()); |
| |
| assertEquals(AttributeOperationType.REMOVE, |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:exported"))); |
| |
| assertEquals(AttributeOperationType.REPLACE, |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme"))); |
| |
| assertEquals(AttributeOperationType.STRICT, |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:windowSoftInputMode"))); |
| } |
| |
| public void testNoNamespaceAwareAttributeInstructions() |
| throws ParserConfigurationException, SAXException, IOException { |
| String input = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " tools:remove=\"theme\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| // ActivityOne, remove operation. |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testAttributeInstructions()"), input); |
| Optional<XmlElement> activityOptional = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne"); |
| assertTrue(activityOptional.isPresent()); |
| XmlElement activity = activityOptional.get(); |
| assertEquals(1, activity.getAttributeOperations().size()); |
| AttributeOperationType attributeOperationType = |
| activity.getAttributeOperationType(XmlNode.fromXmlName("android:theme")); |
| assertEquals(AttributeOperationType.REMOVE, attributeOperationType); |
| } |
| |
| public void testUnusualNamespacePrefixAttributeInstructions() |
| throws ParserConfigurationException, SAXException, IOException { |
| String input = "" |
| + "<manifest\n" |
| + " xmlns:z=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib3\">\n" |
| + "\n" |
| + " <activity z:name=\"activityOne\" tools:remove=\"theme\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| // ActivityOne, remove operation. |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testAttributeInstructions()"), input); |
| Optional<XmlElement> activityOptional = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne"); |
| assertTrue(activityOptional.isPresent()); |
| XmlElement activity = activityOptional.get(); |
| |
| assertEquals(1, activity.getAttributeOperations().size()); |
| AttributeOperationType attributeOperationType = |
| activity.getAttributeOperationType(XmlNode.fromXmlName("z:theme")); |
| assertEquals(AttributeOperationType.REMOVE, attributeOperationType); |
| } |
| |
| public void testInvalidAttributeInstruction() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| String input = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " tools:bad-name=\"android:theme\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| try { |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff6()"), input); |
| xmlDocument.getRootNode(); |
| fail("Exception not thrown"); |
| } catch (RuntimeException expected) { |
| // expected. |
| } |
| } |
| |
| public void testOtherToolsInstruction() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| String input = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " tools:ignore=\"android:theme\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testOtherToolsInstruction"), input); |
| xmlDocument.getRootNode(); |
| } |
| |
| |
| public void testDiff1() |
| throws Exception { |
| |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/apk/res/android/tools\"\n" |
| + " package=\"com.example.lib3\">\n" |
| + "\n" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff1()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff1()"), other); |
| |
| assertFalse(refDocument.getRootNode().getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne").get() |
| .compareTo(otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne") |
| .get()).isPresent()); |
| } |
| |
| public void testDiff2() |
| throws Exception { |
| |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/apk/res/android/tools\"\n" |
| + " package=\"com.example.lib3\">\n" |
| + "\n" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"mcc\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff2()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff2()"), other); |
| |
| assertTrue(refDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get() |
| .compareTo( |
| otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne") |
| .get() |
| ).isPresent()); |
| } |
| |
| public void testDiff3() |
| throws Exception { |
| |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/apk/res/android/tools\"\n" |
| + " package=\"com.example.lib3\">\n" |
| + "\n" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\" android:exported=\"true\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff3()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff3()"), other); |
| |
| assertTrue(refDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get() |
| .compareTo( |
| otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne") |
| .get() |
| ).isPresent()); |
| } |
| |
| public void testDiff4() |
| throws Exception { |
| |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\" android:exported=\"false\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff4()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff4()"), other); |
| assertTrue(refDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get() |
| .compareTo( |
| otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne") |
| .get() |
| ).isPresent()); |
| } |
| |
| public void testDiff5() |
| throws Exception { |
| |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\">\n" |
| + "\n" |
| + " </activity>\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff5()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff5()"), other); |
| |
| assertFalse(refDocument.compareTo(otherDocument).isPresent()); |
| } |
| |
| public void testDiff6() |
| throws Exception { |
| |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\">\n" |
| + "\n" |
| + " <intent-filter android:label=\"@string/foo\"/>\n" |
| + "\n" |
| + " </activity>\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff6()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testDiff6()"), other); |
| assertTrue( |
| refDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get() |
| .compareTo( |
| otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne") |
| .get() |
| ).isPresent() |
| ); |
| } |
| |
| /** |
| * test merging of same element types with no collision. |
| */ |
| public void testMerge_NoCollision() throws ParserConfigurationException, SAXException, IOException { |
| String reference = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\">\n" |
| + " <intent-filter android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String other = "" |
| + "<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" |
| + " <activity android:name=\"activityTwo\" " |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testMerge()"), reference); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "testMerge()"), other); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| XmlDocument resultDocument = result.get(); |
| |
| Optional<XmlElement> activityOne = resultDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOne.isPresent()); |
| |
| Optional<XmlElement> activityTwo = resultDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityTwo"); |
| assertTrue(activityTwo.isPresent()); |
| } |
| |
| /** |
| * test merging of same element with no attribute collision. |
| */ |
| public void testAttributeMerging() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\">\n" |
| + " <intent-filter android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" \n" |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| XmlDocument resultDocument = result.get(); |
| |
| Optional<XmlElement> activityOne = resultDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOne.isPresent()); |
| |
| // verify that both attributes are in the resulting merged element. |
| List<XmlAttribute> attributes = activityOne.get().getAttributes(); |
| assertEquals(2, attributes.size()); |
| assertTrue(activityOne.get().getAttribute( |
| XmlNode.fromXmlName("android:configChanges")).isPresent()); |
| assertTrue(activityOne.get().getAttribute( |
| XmlNode.fromXmlName("android:name")).isPresent()); |
| } |
| |
| /** |
| * test merging of same element with no attribute collision. |
| */ |
| public void testElementRemoval() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" tools:node=\"remove\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" \n" |
| + " android:configChanges=\"locale\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| // run the instruction cleaner to get rid of all unwanted attributes, nodes. |
| XmlDocument resultDocument = ToolsInstructionsCleaner.cleanToolsReferences( |
| result.get(), mergingReportBuilder.getLogger()); |
| |
| Optional<XmlElement> activityOne = resultDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertFalse(activityOne.isPresent()); |
| } |
| |
| /** |
| * test merging of same element with no attribute collision. |
| */ |
| public void testElementReplacement() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" tools:node=\"replace\"" |
| + " android:exported=\"true\"/>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\">\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| XmlDocument resultDocument = result.get(); |
| |
| Optional<XmlElement> activityOne = resultDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOne.isPresent()); |
| |
| Logger.getAnonymousLogger().info(resultDocument.prettyPrint()); |
| |
| |
| assertFalse(refDocument.getRootNode().getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne").get().compareTo(activityOne.get()).isPresent()); |
| } |
| |
| /** |
| * test merging of same element type with STRICT enforcing and no difference between the high |
| * and low priority elements. |
| */ |
| public void testStrictElement_noDifference() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" tools:node=\"strict\"" |
| + " android:exported=\"true\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| XmlDocument resultDocument = result.get(); |
| |
| Optional<XmlElement> activityOne = resultDocument.getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOne.isPresent()); |
| |
| Logger.getAnonymousLogger().info(resultDocument.prettyPrint()); |
| |
| |
| assertFalse(refDocument.getRootNode().getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne").get().compareTo(activityOne.get()).isPresent()); |
| } |
| |
| /** |
| * test merging of same element type with STRICT enforcing and no difference between the high |
| * and low priority elements. |
| */ |
| public void testStrictElement_withDifference() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" tools:node=\"strict\"" |
| + " android:exported=\"true\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| refDocument.merge(otherDocument, mergingReportBuilder); |
| assertEquals(MergingReport.Result.ERROR, mergingReportBuilder.build().getResult()); |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| for (MergingReport.Record record : loggingRecords) { |
| Logger.getAnonymousLogger().info(record.toString()); |
| } |
| assertEquals(1, loggingRecords.size()); |
| |
| } |
| |
| /** |
| * test attributes merging of elements with no conflict between attributes. |
| */ |
| public void testMerging_noConflict() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\">\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <meta-data android:name=\"zoo\" android:value=\"@string/kangaroo\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| Optional<XmlElement> activityOptional = result.get().getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOptional.isPresent()); |
| XmlElement activityOne = activityOptional.get(); |
| assertEquals(3, activityOne.getAttributes().size()); |
| assertEquals(1, activityOne.getMergeableElements().size()); |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| for (MergingReport.Record record : loggingRecords) { |
| Logger.getAnonymousLogger().info(record.toString()); |
| } |
| } |
| |
| /** |
| * test attributes merging of elements with no conflict between attributes. |
| */ |
| public void testMerging_withConflict() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:exported=\"false\">\n" |
| + " <action android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| refDocument.merge(otherDocument, mergingReportBuilder); |
| assertEquals(MergingReport.Result.ERROR, mergingReportBuilder.build().getResult()); |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| for (MergingReport.Record record : loggingRecords) { |
| Logger.getAnonymousLogger().info(record.toString()); |
| } |
| } |
| |
| /** |
| * test attributes merging of elements with no conflict between children. |
| */ |
| public void testMerging_childrenDoNotConflict() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\">\n" |
| + " <meta-data android:name=\"fish\" android:value=\"@string/cod\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <meta-data android:name=\"bird\" android:value=\"@string/eagle\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| Optional<XmlElement> activityOptional = result.get().getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOptional.isPresent()); |
| XmlElement activityOne = activityOptional.get(); |
| assertEquals(3, activityOne.getAttributes().size()); |
| // both metat-data should be present. |
| assertEquals(2, activityOne.getMergeableElements().size()); |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| assertTrue(loggingRecords.isEmpty()); |
| } |
| |
| /** |
| * test attributes merging of elements with some conflicts between children. |
| */ |
| public void testMerging_childrenConflict() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\">\n" |
| + " <meta-data android:name=\"bird\" android:value=\"@string/hawk\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <meta-data android:name=\"bird\" android:value=\"@string/eagle\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertFalse(result.isPresent()); |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| assertEquals(1, loggingRecords.size()); |
| // check the error message complains about the right attribute. |
| assertTrue(loggingRecords.get(0).toString().contains("meta-data#bird@value")); |
| } |
| |
| /** |
| * test attributes merging of elements with some conflicts between children. |
| */ |
| public void testMerging_differentChildrenTypes() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\">\n" |
| + " <meta-data android:name=\"bird\" android:value=\"@string/hawk\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <intent-filter>\n" |
| + " <action android:name=\"android.appwidget.action.APPWIDGET_CONFIGURE\"/>" |
| + " </intent-filter>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| Optional<XmlElement> activityOptional = result.get().getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY, |
| "com.example.lib3.activityOne"); |
| assertTrue(activityOptional.isPresent()); |
| XmlElement activityOne = activityOptional.get(); |
| assertEquals(3, activityOne.getAttributes().size()); |
| // both metat-data and intent-filter should be present. |
| assertEquals(2, activityOne.getMergeableElements().size()); |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| assertTrue(loggingRecords.isEmpty()); |
| } |
| |
| /** |
| * test attributes merging of elements with some conflicts between children. |
| */ |
| public void testHigherPriorityDefaultValue_NoOverride() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"dangerous\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| Optional<XmlElement> activityOptional = result.get().getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.PERMISSION, "permissionOne"); |
| assertTrue(activityOptional.get() |
| .getAttribute(XmlNode.fromXmlName("android:protectionLevel")).isPresent()); |
| } |
| |
| /** |
| * test attributes merging of elements with some conflicts between children. |
| */ |
| public void testLowerPriorityDefaultValue_NoOverride() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"\n" |
| + " android:protectionLevel=\"dangerous\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\">" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| Optional<XmlElement> activityOptional = result.get().getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.PERMISSION, "permissionOne"); |
| assertTrue(activityOptional.get() |
| .getAttribute(XmlNode.fromXmlName("android:protectionLevel")).isPresent()); |
| } |
| |
| /** |
| * test attributes merging of elements with some conflicts between children. |
| */ |
| public void testHigherPriorityDefaultValue_SameOverride() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| Optional<XmlElement> activityOptional = result.get().getRootNode() |
| .getNodeByTypeAndKey(ManifestModel.NodeTypes.PERMISSION, "permissionOne"); |
| assertTrue(activityOptional.get() |
| .getAttribute(XmlNode.fromXmlName("android:protectionLevel")).isPresent()); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testRemoveAll_severalTargets() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission tools:node=\"removeAll\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionTwo\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionThree\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| assertEquals(1, mergeableElements.size()); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testRemoveAll_oneTarget() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission tools:node=\"removeAll\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| assertEquals(1, mergeableElements.size()); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testRemoveAll_noTarget() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission tools:node=\"removeAll\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| assertEquals(1, mergeableElements.size()); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testMergeOnlyAttributes() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\" " |
| + " android:exported=\"true\"" |
| + " tools:node=\"mergeOnlyAttributes\">\n" |
| + " <meta-data android:name=\"bird\" android:value=\"@string/hawk\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriority = "" |
| + "<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" |
| + " <activity android:name=\"activityOne\"\n" |
| + " android:screenOrientation=\"landscape\">\n" |
| + " <meta-data android:name=\"dog\" android:value=\"@string/dog\" />\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriority"), lowerPriority); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(otherDocument, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| Optional<XmlElement> activityOne = result.get().getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne"); |
| assertTrue(activityOne.isPresent()); |
| |
| assertEquals(1, activityOne.get().getMergeableElements().size()); |
| assertEquals(4, activityOne.get().getAttributes().size()); |
| |
| // check that we kept the right child from the higher priority node. |
| XmlNode.NodeName nodeName = XmlNode.fromXmlName( |
| SdkConstants.ANDROID_NS_NAME_PREFIX + SdkConstants.ATTR_NAME); |
| assertEquals("bird", activityOne.get().getMergeableElements().get(0) |
| .getAttribute(nodeName).get().getValue()); |
| |
| // check the records. |
| Actions actionRecorder = mergingReportBuilder.getActionRecorder().build(); |
| assertEquals(3, actionRecorder.getNodeKeys().size()); |
| ImmutableList<NodeRecord> nodeRecords = actionRecorder.getNodeRecords( |
| new XmlNode.NodeKey("activity#com.example.lib3.activityOne")); |
| for (NodeRecord nodeRecord : nodeRecords) { |
| if ("meta-data#dog".equals(nodeRecord.getTargetId().toString())) { |
| assertEquals(Actions.ActionType.REJECTED, |
| nodeRecord.getActionType()); |
| return; |
| } |
| } |
| fail("Did not find the meta-data rejection record"); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testRemove_withSelector() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"" |
| + " tools:node=\"remove\"" |
| + " tools:selector=\"com.example.lib1\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityOne = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib1\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"signature\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityTwo = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib2\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionTwo\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| KeyResolver<String> keyResolver = (KeyResolver<String>) Mockito.mock(KeyResolver.class); |
| when(keyResolver.resolve(any(String.class))).thenReturn("valid"); |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString(keyResolver, |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument firstLibrary = TestUtils.xmlDocumentFromString(keyResolver, |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityOne"), lowerPriorityOne); |
| XmlDocument secondLibrary = TestUtils.xmlDocumentFromString(keyResolver, |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityTwo"), lowerPriorityTwo); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(firstLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| result = result.get().merge(secondLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| assertEquals(2, mergeableElements.size()); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testRemoveAll_withSelector() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission" |
| + " tools:node=\"removeAll\"\n" |
| + " tools:selector=\"com.example.lib1\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityOne = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib1\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"signature\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionTwo\"" |
| + " android:protectionLevel=\"signature\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityTwo = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib2\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionThree\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionFour\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument firstLibrary = TestUtils.xmlLibraryFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityOne"), lowerPriorityOne); |
| XmlDocument secondLibrary = TestUtils.xmlLibraryFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityTwo"), lowerPriorityTwo); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(firstLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| result = result.get().merge(secondLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| assertEquals(3, mergeableElements.size()); |
| XmlNode.NodeName nodeName = XmlNode.fromXmlName("android:name"); |
| assertEquals("permissionThree", |
| mergeableElements.get(1).getAttribute(nodeName).get().getValue()); |
| assertEquals("permissionFour", |
| mergeableElements.get(2).getAttribute(nodeName).get().getValue()); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testInvalidSelector() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission android:name=\"permissionOne\"" |
| + " tools:node=\"remove\"" |
| + " tools:selector=\"com.example.libXYZ\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityOne = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib1\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"signature\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument firstLibrary = TestUtils.xmlLibraryFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityOne"), lowerPriorityOne); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(firstLibrary, mergingReportBuilder); |
| assertFalse(result.isPresent()); |
| |
| ImmutableList<MergingReport.Record> loggingRecords = mergingReportBuilder.build() |
| .getLoggingRecords(); |
| assertEquals(1, loggingRecords.size()); |
| assertEquals(MergingReport.Record.Severity.ERROR, loggingRecords.get(0).getSeverity()); |
| assertTrue(loggingRecords.get(0).getMessage().contains("tools:selector")); |
| } |
| |
| /** |
| * test tools:node="removeAll" with several target elements to be removed. |
| */ |
| public void testRemoveAndRemoveAll_withReplace() |
| throws ParserConfigurationException, SAXException, IOException { |
| String higherPriority = "" |
| + "<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" |
| + " <permission" |
| + " android:name=\"permissionOne\"\n" |
| + " tools:node=\"remove\"\n" |
| + " tools:selector=\"com.example.lib1\">\n" |
| + " </permission>\n" |
| + " <permission" |
| + " tools:node=\"removeAll\"\n" |
| + " tools:selector=\"com.example.lib3\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionThree\"" |
| + " android:protectionLevel=\"signature\"" |
| + " tools:node=\"replace\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityOne = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib1\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionOne\"" |
| + " android:protectionLevel=\"signature\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionTwo\"" |
| + " android:protectionLevel=\"signature\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityTwo = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib2\">\n" |
| + "\n" |
| + " <permission android:name=\"permissionThree\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + " <permission android:name=\"permissionFour\"" |
| + " android:protectionLevel=\"normal\">\n" |
| + " </permission>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| XmlDocument firstLibrary = TestUtils.xmlLibraryFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityOne"), lowerPriorityOne); |
| XmlDocument secondLibrary = TestUtils.xmlLibraryFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityTwo"), lowerPriorityTwo); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(firstLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| result = result.get().merge(secondLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| // I should have permissionTwo, permissionThree (replaced), permissionFour |
| // + remove and removeAll not cleaned |
| assertEquals(5, mergeableElements.size()); |
| XmlNode.NodeName nodeName = XmlNode.fromXmlName("android:name"); |
| for (int i = 0; i < 5; i++) { |
| XmlElement xmlElement = mergeableElements.get(i); |
| Optional<XmlAttribute> optionalName = xmlElement.getAttribute(nodeName); |
| if (!optionalName.isPresent()) { |
| continue; |
| } |
| String elementName = optionalName.get().getValue(); |
| if (elementName.equals("permissionThree")) { |
| assertEquals("signature", xmlElement.getAttribute( |
| XmlNode.fromXmlName("android:protectionLevel")).get().getValue()); |
| } else { |
| if (!elementName.equals("permissionOne") && !elementName.equals("permissionTwo") |
| && !elementName.equals("permissionFour")) { |
| fail("Unexepected permission " + elementName); |
| } |
| } |
| |
| } |
| } |
| |
| public void testCompatibleScreens() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| String higherPriority = "" |
| + "<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" |
| + " <compatible-screens>\n" |
| + " <!-- all small size screens -->\n" |
| + " <screen android:screenSize=\"small\" android:screenDensity=\"ldpi\" />\n" |
| + " <screen android:screenSize=\"small\" android:screenDensity=\"mdpi\" />\n" |
| + " <screen android:screenSize=\"small\" android:screenDensity=\"xhdpi\" />\n" |
| + " <!-- all normal size screens -->\n" |
| + " <screen android:screenSize=\"normal\" android:screenDensity=\"ldpi\" />\n" |
| + " <screen android:screenSize=\"normal\" android:screenDensity=\"hdpi\" />\n" |
| + " <screen android:screenSize=\"normal\" android:screenDensity=\"xhdpi\" />\n" |
| + " </compatible-screens>" |
| + "\n" |
| + "</manifest>"; |
| |
| String lowerPriorityOne = "" |
| + "<manifest\n" |
| + " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" |
| + " xmlns:tools=\"http://schemas.android.com/tools\"\n" |
| + " package=\"com.example.lib1\">\n" |
| + "\n" |
| + " <compatible-screens>\n" |
| + " <!-- all small size screens -->\n" |
| + " <screen android:screenSize=\"small\" android:screenDensity=\"ldpi\" />\n" |
| + " <screen android:screenSize=\"small\" android:screenDensity=\"mdpi\" />\n" |
| + " <screen android:screenSize=\"small\" android:screenDensity=\"hdpi\" />\n" |
| + " <!-- all normal size screens -->\n" |
| + " <screen android:screenSize=\"normal\" android:screenDensity=\"mdpi\" />\n" |
| + " <screen android:screenSize=\"normal\" android:screenDensity=\"hdpi\" />\n" |
| + " <screen android:screenSize=\"normal\" android:screenDensity=\"xhdpi\" />\n" |
| + " </compatible-screens>" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument refDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), "higherPriority"), higherPriority); |
| |
| XmlDocument firstLibrary = TestUtils.xmlLibraryFromString( |
| new TestUtils.TestSourceLocation(getClass(), "lowerPriorityOne"), lowerPriorityOne); |
| |
| MergingReport.Builder mergingReportBuilder = new MergingReport.Builder( |
| new StdLogger(StdLogger.Level.VERBOSE)); |
| Optional<XmlDocument> result = refDocument.merge(firstLibrary, mergingReportBuilder); |
| assertTrue(result.isPresent()); |
| |
| ImmutableList<XmlElement> mergeableElements = result.get().getRootNode() |
| .getMergeableElements(); |
| |
| assertEquals(1, mergeableElements.size()); |
| ImmutableList<XmlElement> mergedScreens = mergeableElements.get(0) |
| .getMergeableElements(); |
| |
| // we should have merged screens with no duplicated elements. |
| assertEquals(8, mergedScreens.size()); |
| } |
| } |