| /* |
| * 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.utils.ILogger; |
| |
| 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 javax.xml.parsers.ParserConfigurationException; |
| |
| /** |
| * Tests for the {@link ActionRecorder} class |
| */ |
| public class ActionRecorderTest extends TestCase { |
| |
| private static final String REFERENCE = "" |
| + "<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\">\n" |
| + " <intent-filter android:label=\"@string/foo\"/>\n" |
| + " </activity>\n" |
| + "\n" |
| + "</manifest>"; |
| |
| |
| // this will be used as the source location for the "reference" xml string. |
| private static final String REFEFENCE_DOCUMENT = "ref_doc"; |
| |
| @Mock ILogger mLoggerMock; |
| |
| ActionRecorder mActionRecorderBuilder = new ActionRecorder(); |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| MockitoAnnotations.initMocks(this); |
| } |
| |
| public void testDoNothing() { |
| Actions actions = mActionRecorderBuilder.build(); |
| actions.log(mLoggerMock); |
| Mockito.verify(mLoggerMock).verbose(Actions.HEADER); |
| Mockito.verifyNoMoreInteractions(mLoggerMock); |
| assertTrue(actions.getNodeKeys().isEmpty()); |
| } |
| |
| public void testSingleElement_withoutAttributes() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| REFEFENCE_DOCUMENT), REFERENCE); |
| |
| XmlElement xmlElement = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get(); |
| // added during the initial file loading |
| mActionRecorderBuilder.recordNodeAction(xmlElement, Actions.ActionType.ADDED); |
| |
| Actions actions = mActionRecorderBuilder.build(); |
| assertEquals(1, actions.getNodeKeys().size()); |
| assertEquals(1, actions.getNodeRecords(xmlElement.getId()).size()); |
| assertEquals(0, actions.getRecordedAttributeNames(xmlElement.getId()).size()); |
| actions.log(mLoggerMock); |
| |
| // check that output is consistent with spec. |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append(Actions.HEADER) |
| .append(xmlElement.getId()).append("\n"); |
| appendNode(stringBuilder, Actions.ActionType.ADDED, REFEFENCE_DOCUMENT, 6, 5); |
| |
| Mockito.verify(mLoggerMock).verbose(stringBuilder.toString()); |
| Mockito.verifyNoMoreInteractions(mLoggerMock); |
| } |
| |
| public void testSingleElement_withoutAttributes_withRejection() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| 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 xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| REFEFENCE_DOCUMENT), REFERENCE); |
| |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| "other_document"), other); |
| |
| XmlElement xmlElement = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get(); |
| // added during initial document loading |
| mActionRecorderBuilder.recordNodeAction(xmlElement, Actions.ActionType.ADDED); |
| // rejected during second document merging. |
| mActionRecorderBuilder.recordNodeAction(xmlElement, Actions.ActionType.REJECTED, |
| otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get()); |
| |
| Actions actions = mActionRecorderBuilder.build(); |
| assertEquals(1, actions.getNodeKeys().size()); |
| assertEquals(2, actions.getNodeRecords(xmlElement.getId()).size()); |
| assertEquals(Actions.ActionType.ADDED, |
| actions.getNodeRecords(xmlElement.getId()).get(0).mActionType); |
| assertEquals(Actions.ActionType.REJECTED, |
| actions.getNodeRecords(xmlElement.getId()).get(1).mActionType); |
| assertEquals(0, actions.getRecordedAttributeNames(xmlElement.getId()).size()); |
| actions.log(mLoggerMock); |
| |
| // check that output is consistent with spec. |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append(Actions.HEADER) |
| .append(xmlElement.getId()).append("\n"); |
| appendNode(stringBuilder, Actions.ActionType.ADDED, REFEFENCE_DOCUMENT, 6, 5); |
| appendNode(stringBuilder, Actions.ActionType.REJECTED, "other_document", 6, 5); |
| |
| Mockito.verify(mLoggerMock).verbose(stringBuilder.toString()); |
| Mockito.verifyNoMoreInteractions(mLoggerMock); |
| } |
| |
| public void testSingleElement_withNoNamespaceAttributes() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| REFEFENCE_DOCUMENT), REFERENCE); |
| |
| XmlElement xmlElement = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get(); |
| // added during the initial file loading |
| mActionRecorderBuilder.recordNodeAction(xmlElement, Actions.ActionType.ADDED); |
| mActionRecorderBuilder.recordAttributeAction( |
| xmlElement.getAttribute(XmlNode.fromXmlName("android:name")).get(), |
| Actions.ActionType.ADDED, AttributeOperationType.STRICT); |
| |
| Actions actions = mActionRecorderBuilder.build(); |
| assertEquals(1, actions.getNodeKeys().size()); |
| assertEquals(1, actions.getNodeRecords(xmlElement.getId()).size()); |
| assertEquals(1, actions.getRecordedAttributeNames(xmlElement.getId()).size()); |
| actions.log(mLoggerMock); |
| |
| // check that output is consistent with spec. |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append(Actions.HEADER) |
| .append(xmlElement.getId()).append("\n"); |
| appendNode(stringBuilder, Actions.ActionType.ADDED, REFEFENCE_DOCUMENT, 6, 5); |
| appendAttribute(stringBuilder, |
| XmlNode.unwrapName(xmlElement.getXml().getAttributeNode("android:name")), |
| Actions.ActionType.ADDED, |
| REFEFENCE_DOCUMENT, |
| 6, |
| 15); |
| |
| Mockito.verify(mLoggerMock).verbose(stringBuilder.toString()); |
| Mockito.verifyNoMoreInteractions(mLoggerMock); |
| } |
| |
| public void testSingleElement_withNamespaceAttributes() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| REFEFENCE_DOCUMENT), REFERENCE); |
| |
| XmlElement xmlElement = xmlDocument.getRootNode(); |
| // added during the initial file loading |
| mActionRecorderBuilder.recordNodeAction(xmlElement, Actions.ActionType.ADDED); |
| mActionRecorderBuilder.recordAttributeAction( |
| xmlElement.getAttribute(XmlNode.fromXmlName("package")).get(), |
| Actions.ActionType.ADDED, AttributeOperationType.STRICT); |
| |
| Actions actions = mActionRecorderBuilder.build(); |
| assertEquals(1, actions.getNodeKeys().size()); |
| assertEquals(1, actions.getNodeRecords(xmlElement.getId()).size()); |
| assertEquals(1, actions.getRecordedAttributeNames(xmlElement.getId()).size()); |
| actions.log(mLoggerMock); |
| |
| // check that output is consistent with spec. |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append(Actions.HEADER) |
| .append(xmlElement.getId()).append("\n"); |
| appendNode(stringBuilder, Actions.ActionType.ADDED, REFEFENCE_DOCUMENT, 1, 1); |
| appendAttribute(stringBuilder, |
| XmlNode.unwrapName(xmlElement.getXml().getAttributeNode("package")), |
| Actions.ActionType.ADDED, |
| REFEFENCE_DOCUMENT, |
| 4, |
| 5); |
| |
| Mockito.verify(mLoggerMock).verbose(stringBuilder.toString()); |
| Mockito.verifyNoMoreInteractions(mLoggerMock); |
| } |
| |
| public void testMultipleElements_withRejection() |
| throws ParserConfigurationException, SAXException, IOException { |
| |
| 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" |
| + " <application android:name=\"applicationOne\"/>" |
| + "\n" |
| + "</manifest>"; |
| |
| XmlDocument xmlDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| REFEFENCE_DOCUMENT), REFERENCE); |
| |
| XmlDocument otherDocument = TestUtils.xmlDocumentFromString( |
| new TestUtils.TestSourceLocation(getClass(), |
| "other_document"), other); |
| |
| XmlElement activityElement = xmlDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get(); |
| // added during initial document loading |
| mActionRecorderBuilder.recordNodeAction(activityElement, Actions.ActionType.ADDED); |
| // rejected during second document merging. |
| mActionRecorderBuilder.recordNodeAction(activityElement, Actions.ActionType.REJECTED, |
| otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").get()); |
| XmlElement applicationElement = otherDocument.getRootNode().getNodeByTypeAndKey( |
| ManifestModel.NodeTypes.APPLICATION, null).get(); |
| mActionRecorderBuilder.recordNodeAction(applicationElement, Actions.ActionType.ADDED); |
| |
| Actions actions = mActionRecorderBuilder.build(); |
| assertEquals(2, actions.getNodeKeys().size()); |
| assertEquals(2, actions.getNodeRecords(activityElement.getId()).size()); |
| assertEquals(Actions.ActionType.ADDED, |
| actions.getNodeRecords(activityElement.getId()).get(0).mActionType); |
| assertEquals(Actions.ActionType.REJECTED, |
| actions.getNodeRecords(activityElement.getId()).get(1).mActionType); |
| assertEquals(0, actions.getRecordedAttributeNames(activityElement.getId()).size()); |
| assertEquals(1, actions.getNodeRecords(applicationElement.getId()).size()); |
| assertEquals(0, actions.getRecordedAttributeNames(applicationElement.getId()).size()); |
| actions.log(mLoggerMock); |
| |
| // check that output is consistent with spec. |
| StringBuilder stringBuilder = new StringBuilder(); |
| stringBuilder.append(Actions.HEADER) |
| .append(activityElement.getId()).append("\n"); |
| appendNode(stringBuilder, Actions.ActionType.ADDED, REFEFENCE_DOCUMENT, 6, 5); |
| appendNode(stringBuilder, Actions.ActionType.REJECTED, "other_document", 6, 5); |
| stringBuilder.append(applicationElement.getId()).append("\n"); |
| appendNode(stringBuilder, Actions.ActionType.ADDED, "other_document", 7, 5); |
| |
| Mockito.verify(mLoggerMock).verbose(stringBuilder.toString()); |
| Mockito.verifyNoMoreInteractions(mLoggerMock); |
| } |
| |
| private void appendNode(StringBuilder out, |
| Actions.ActionType actionType, |
| String docString, |
| int lineNumber, |
| int columnNumber) { |
| |
| out.append(actionType.toString()) |
| .append(" from ") |
| .append(getClass().getSimpleName()).append('#').append(docString) |
| .append(":").append(lineNumber).append(":").append(columnNumber).append("\n"); |
| } |
| |
| private void appendAttribute(StringBuilder out, |
| XmlNode.NodeName attributeName, |
| Actions.ActionType actionType, |
| String docString, |
| int lineNumber, |
| int columnNumber) { |
| |
| out.append("\t") |
| .append(attributeName.toString()) |
| .append("\n\t\t") |
| .append(actionType.toString()) |
| .append(" from ") |
| .append(getClass().getSimpleName()).append('#').append(docString) |
| .append(":").append(lineNumber) |
| .append(":").append(columnNumber).append("\n"); |
| } |
| } |