/*
* 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.MergingReport.Record.Severity.ERROR;
import com.android.SdkConstants;
import com.android.sdklib.SdkVersionInfo;
import com.android.sdklib.mock.MockLog;
import com.android.utils.ILogger;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import junit.framework.TestCase;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
/**
* Tests for {@link com.android.manifmerger.XmlDocument}
*/
public class XmlDocumentTest extends TestCase {
@Mock ILogger mLogger;
@Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
}
public void testMergeableElementsIdentification()
throws ParserConfigurationException, SAXException, IOException {
String input = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument xmlDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testMergeableElementsIdentification()"), input);
ImmutableList<XmlElement> mergeableElements = xmlDocument.getRootNode().getMergeableElements();
assertEquals(2, mergeableElements.size());
}
public void testNamespaceEnabledElements()
throws ParserConfigurationException, SAXException, IOException {
String input = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <android:application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ " <android:activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument xmlDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testMergeableElementsIdentification()"), input);
ImmutableList<XmlElement> mergeableElements = xmlDocument.getRootNode().getMergeableElements();
assertEquals(2, mergeableElements.size());
assertEquals(ManifestModel.NodeTypes.APPLICATION, mergeableElements.get(0).getType());
assertEquals(ManifestModel.NodeTypes.ACTIVITY, mergeableElements.get(1).getType());
}
public void testMultipleNamespaceEnabledElements()
throws ParserConfigurationException, SAXException, IOException {
String input = ""
+ "<android:manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:tools=\"http://schemas.android.com/tools\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <android:application android:label=\"@string/lib_name\" \n"
+ " tools:node=\"replace\" />\n"
+ " <acme:custom-tag android:label=\"@string/lib_name\" />\n"
+ " <acme:application acme:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</android:manifest>";
XmlDocument xmlDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testMergeableElementsIdentification()"), input);
ImmutableList<XmlElement> mergeableElements = xmlDocument.getRootNode().getMergeableElements();
assertEquals(3, mergeableElements.size());
assertEquals(ManifestModel.NodeTypes.APPLICATION, mergeableElements.get(0).getType());
assertEquals(ManifestModel.NodeTypes.CUSTOM, mergeableElements.get(1).getType());
assertEquals(ManifestModel.NodeTypes.CUSTOM, mergeableElements.get(2).getType());
}
public void testGetXmlNodeByTypeAndKey()
throws ParserConfigurationException, SAXException, IOException {
String input = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument xmlDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testGetXmlNodeByTypeAndKey()"), input);
assertTrue(xmlDocument.getRootNode().getNodeByTypeAndKey(
ManifestModel.NodeTypes.ACTIVITY, "com.example.lib3.activityOne").isPresent());
assertFalse(xmlDocument.getRootNode().getNodeByTypeAndKey(
ManifestModel.NodeTypes.ACTIVITY, "noName").isPresent());
}
public void testSimpleMerge()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testSimpleMerge()"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "testSimpleMerge()"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
Logger.getAnonymousLogger().info(mergedDocument.get().prettyPrint());
assertTrue(mergedDocument.get().getRootNode().getNodeByTypeAndKey(
ManifestModel.NodeTypes.APPLICATION, null).isPresent());
Optional<XmlElement> activityOne = mergedDocument.get()
.getRootNode().getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY,
"com.example.lib3.activityOne");
assertTrue(activityOne.isPresent());
}
public void testDiff1()
throws Exception {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testDiff1()"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "testDiff1()"), library);
assertTrue(mainDocument.compareTo(libraryDocument).isPresent());
}
public void testDiff2()
throws Exception {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testDiff2()"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "testDiff2()"), library);
assertFalse(mainDocument.compareTo(libraryDocument).isPresent());
}
public void testDiff3()
throws Exception {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <!-- some comment that should be ignored -->\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <!-- some comment that should also be ignored -->\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testDiff3()"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "testDiff3()"), library);
assertFalse(mainDocument.compareTo(libraryDocument).isPresent());
}
public void testWriting() throws ParserConfigurationException, SAXException, IOException {
String input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:x=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:y=\"http://schemas.android.com/apk/res/android/tools\"\n"
+ " package=\"com.example.lib3\" >\n"
+ "\n"
+ " <application\n"
+ " x:label=\"@string/lib_name\"\n"
+ " y:node=\"replace\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument xmlDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "testWriting()"), input);
assertEquals(input, xmlDocument.prettyPrint());
}
public void testCustomElements()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <fantasy android:name=\"fantasyOne\" \n"
+ " no-ns-attribute=\"no-ns\" >\n"
+ " </fantasy>\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <fantasy android:name=\"fantasyTwo\" \n"
+ " no-ns-attribute=\"no-ns\" >\n"
+ " </fantasy>\n"
+ " <acme:another acme:name=\"anotherOne\" \n"
+ " acme:ns-attribute=\"ns-value\" >\n"
+ " <some-child acme:child-attr=\"foo\" /> \n"
+ " </acme:another>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlElement rootNode = mergedDocument.get().getRootNode();
assertTrue(rootNode.getNodeByTypeAndKey(
ManifestModel.NodeTypes.APPLICATION, null).isPresent());
Optional<XmlElement> activityOne = rootNode
.getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY,
"com.example.lib3.activityOne");
assertTrue(activityOne.isPresent());
boolean foundFantasyOne = false;
boolean foundFantasyTwo = false;
boolean foundAnother = false;
NodeList childNodes = rootNode.getXml().getChildNodes();
for (int i =0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
if (item.getNodeName().equals("fantasy")) {
String name = ((Element) item).getAttributeNS(SdkConstants.ANDROID_URI, "name");
if (name.equals("fantasyOne"))
foundFantasyOne = true;
if (name.equals("fantasyTwo"))
foundFantasyTwo = true;
}
if (item.getNodeName().equals("acme:another")) {
foundAnother = true;
}
}
assertTrue(foundAnother);
assertTrue(foundFantasyOne);
assertTrue(foundFantasyTwo);
Element validated = validate(mergedDocument.get().prettyPrint());
// make sure acme: namespace is defined.
Node namedItem = validated.getAttributes().getNamedItem("xmlns:acme");
assertEquals(namedItem.getNodeValue(), "http://acme.org/schemas");
}
public void testMultipleCustomElements()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " xmlns:acme2=\"http://acme2.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <acme:another acme:name=\"anotherOne\" \n"
+ " acme:ns-attribute=\"ns-value\" >\n"
+ " <acme:some-child acme:child-attr=\"foo\" /> \n"
+ " </acme:another>\n"
+ " <acme:another2 acme:name=\"anotherOne\" \n"
+ " acme:ns-attribute=\"ns-value\" >\n"
+ " <acme:some-child acme:child-attr=\"foo\" /> \n"
+ " </acme:another2>\n"
+ " <acme2:another acme2:name=\"anotherOne\" \n"
+ " acme2:ns-attribute=\"ns-value\" >\n"
+ " <acme2:some-child acme2:child-attr=\"foo\" /> \n"
+ " </acme2:another>\n"
+ " <acme2:another2 acme2:name=\"anotherOne\" \n"
+ " acme2:ns-attribute=\"ns-value\" >\n"
+ " <acme2:some-child acme2:child-attr=\"foo\" /> \n"
+ " </acme2:another2>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlElement rootNode = mergedDocument.get().getRootNode();
assertTrue(rootNode.getNodeByTypeAndKey(
ManifestModel.NodeTypes.APPLICATION, null).isPresent());
Optional<XmlElement> activityOne = rootNode
.getNodeByTypeAndKey(ManifestModel.NodeTypes.ACTIVITY,
"com.example.lib3.activityOne");
assertTrue(activityOne.isPresent());
Element validated = validate(mergedDocument.get().prettyPrint());
// make sure acme: and acme2: namespaces are defined.
Node namedItem = validated.getAttributes().getNamedItem("xmlns:acme");
assertEquals(namedItem.getNodeValue(), "http://acme.org/schemas");
namedItem = validated.getAttributes().getNamedItem("xmlns:acme2");
assertEquals(namedItem.getNodeValue(), "http://acme2.org/schemas");
// check we have all the children we expected.
int elementsNumber = 0;
for (int i = 0; i < validated.getChildNodes().getLength(); i++) {
Node item = validated.getChildNodes().item(i);
if (item instanceof Element) {
elementsNumber++;
}
}
assertEquals(6, elementsNumber);
}
public void testIllegalLibraryVersionMerge()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"4\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertFalse(mergedDocument.isPresent());
MergingReport mergingReport = mergingReportBuilder.build();
assertEquals(1, mergingReport.getLoggingRecords().size());
assertTrue(mergingReport.getLoggingRecords().get(0).getSeverity() == ERROR);
assertTrue(mergingReport.getLoggingRecords().get(0).toString().contains(
"uses-sdk:minSdkVersion 4"));
}
public void testNoMergingNecessary()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testNoUsesSdkPresence()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testGlEsVersionFromFlavor()
throws ParserConfigurationException, SAXException, IOException {
String flavor = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <uses-feature\n"
+ " android:name=\"android.hardware.camera\"\n"
+ " android:glEsVersion=\"0x00020000\"\n"
+ " android:required=\"true\" />"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument flavorDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "flavor"), flavor);
XmlDocument mainDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "main"), main);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
flavorDocument.merge(mainDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
System.out.println(mergedDocument.get().prettyPrint());
XmlDocument xmlDocument = mergedDocument.get();
Optional<XmlElement> usesFeature = xmlDocument
.getByTypeAndKey(ManifestModel.NodeTypes.USES_FEATURE,
"android.hardware.camera");
assertTrue(usesFeature.isPresent());
Optional<XmlAttribute> glEsVersion = usesFeature.get()
.getAttribute(XmlNode.fromXmlName("android:glEsVersion"));
assertTrue(glEsVersion.isPresent());
assertEquals("0x00020000", glEsVersion.get().getValue());
}
public void testNoUsesSdkPresenceInMain()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertFalse(mergedDocument.isPresent());
}
public void testNoUsesSdkPresenceInLibrary()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testLibraryVersion3Merge()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
// check records.
Actions actions = mergingReportBuilder.getActionRecorder().build();
XmlElement xmlElement = xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").get();
ImmutableList<Actions.NodeRecord> nodeRecords = actions
.getNodeRecords(XmlNode.NodeKey.fromXml(xmlElement.getXml()));
assertEquals(1, nodeRecords.size());
assertEquals(nodeRecords.iterator().next().mReason,
"com.example.lib3 has a targetSdkVersion < 4");
}
public void testLibraryVersion10Merge()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"10\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testLibraryVersion3MergeWithContacts()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"3\"/>\n"
+ " <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n"
+ " <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
// check records.
Actions actions = mergingReportBuilder.getActionRecorder().build();
XmlElement xmlElement = xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").get();
ImmutableList<Actions.NodeRecord> nodeRecords = actions
.getNodeRecords(XmlNode.NodeKey.fromXml(xmlElement.getXml()));
assertEquals(1, nodeRecords.size());
assertEquals(nodeRecords.iterator().next().mReason,
"com.example.lib3 has a targetSdkVersion < 4");
xmlElement = xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").get();
nodeRecords = actions.getNodeRecords(XmlNode.NodeKey.fromXml(xmlElement.getXml()));
assertEquals(1, nodeRecords.size());
assertEquals(nodeRecords.iterator().next().mReason,
"com.example.lib3 has targetSdkVersion < 16 and requested READ_CONTACTS");
}
public void testLibraryVersion3MergeWithoutContacts()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ " <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n"
+ " <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testLibraryVersion10MergeWithContacts()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"10\"/>\n"
+ " <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n"
+ " <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testLibraryAtVersion10MergeWithContactsInMain()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ " <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n"
+ " <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"10\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
// no permissions should be added since the library did not add the permissions itself.
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
}
public void testUsesSdkAbsenceInOverlay()
throws ParserConfigurationException, SAXException, IOException {
String overlay = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n"
+ " <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n"
+ "\n"
+ "</manifest>";
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <uses-sdk android:minSdkVersion=\"15\"/>\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <activity android:name=\"activityOne\" />\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "overlay"),
overlay,
XmlDocument.Type.OVERLAY,
Optional.of("com.example.lib3"));
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "main"), main);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
MockLog mockLog = new MockLog();
mergingReportBuilder.build().log(mockLog);
System.out.println(mockLog.toString());
assertTrue(mergedDocument.isPresent());
}
/**
* test illegal importation of a preview library (using the minSdk attribute) in a released
* application.
*/
public void testLibraryAtPreviewInOldApp_usingMinSdk()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertFalse(mergedDocument.isPresent());
MergingReport mergingReport = mergingReportBuilder.build();
ImmutableList<MergingReport.Record> loggingRecords = mergingReport.getLoggingRecords();
assertTrue(mergingReport.getResult().isError());
assertEquals(1, loggingRecords.size());
assertTrue(loggingRecords.get(0).getMessage().contains("XYZ"));
}
/**
* test illegal importation of a preview library (using the minSdk attribute) in a released
* application.
*/
public void testLibraryAtPreviewInNewerApp_usingMinSdk()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\""
+ (SdkVersionInfo.HIGHEST_KNOWN_API + 2) // fantasy version in the far future.
+ "\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertFalse(mergedDocument.isPresent());
MergingReport mergingReport = mergingReportBuilder.build();
ImmutableList<MergingReport.Record> loggingRecords = mergingReport.getLoggingRecords();
assertTrue(mergingReport.getResult().isError());
assertEquals(1, loggingRecords.size());
assertTrue(loggingRecords.get(0).getMessage().contains("XYZ"));
}
/**
* test illegal importation of a preview library (using the targetSdk attribute) in a released
* application.
*/
public void testLibraryAtPreviewInOldApp_usingTargetSdk()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"14\" android:targetSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"14\" android:targetSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertFalse(mergedDocument.isPresent());
MergingReport mergingReport = mergingReportBuilder.build();
ImmutableList<MergingReport.Record> loggingRecords = mergingReport.getLoggingRecords();
assertTrue(mergingReport.getResult().isError());
assertEquals(1, loggingRecords.size());
assertTrue(loggingRecords.get(0).getMessage().contains("XYZ"));
}
/**
* test legal importation of a released library (using the minSdk attribute) into a preview
* application.
*/
public void testLibraryAtReleaseAgainstAppInPreview_usingMinSdk()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"19\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
// make sure the resulting min version is "XYZ".
Optional<XmlElement> usesSdk = mergedDocument.get()
.getByTypeAndKey(ManifestModel.NodeTypes.USES_SDK, null);
Optional<XmlAttribute> attribute = usesSdk.get()
.getAttribute(XmlNode.fromXmlName("android:minSdkVersion"));
assertTrue(attribute.isPresent());
assertEquals("XYZ", attribute.get().getValue());
}
/**
* test legal importation of a released library (using the minSdk attribute) into a preview
* application.
*/
public void testLibraryAtReleaseAgainstAppInPreview_usingTargetSdk()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"14\" android:targetSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\"14\" android:targetSdkVersion=\"14\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
// make sure the resulting target version is "XYZ".
Optional<XmlElement> usesSdk = mergedDocument.get()
.getByTypeAndKey(ManifestModel.NodeTypes.USES_SDK, null);
Optional<XmlAttribute> attribute = usesSdk.get()
.getAttribute(XmlNode.fromXmlName("android:targetSdkVersion"));
assertTrue(attribute.isPresent());
assertEquals("XYZ", attribute.get().getValue());
}
/**
* test illegal importation of a more recent released library (using the minSdk attribute) into
* an older preview application.
*/
public void testLibraryMoreRecentThanCodeName()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:minSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:minSdkVersion=\""
+ (SdkVersionInfo.HIGHEST_KNOWN_API + 2) // fantasy version in the far future.
+ "\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertFalse(mergedDocument.isPresent());
}
/**
* Test that implicit elements are added correctly when importing an old library into a preview
* application.
*/
public void testLibraryVersion3MergeInPreviewApp()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application android:label=\"@string/lib_name\" />\n"
+ " <uses-sdk android:targetSdkVersion=\"XYZ\"/>\n"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_EXTERNAL_STORAGE").isPresent());
assertTrue(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_PHONE_STATE").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.READ_CALL_LOG").isPresent());
assertFalse(xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_CALL_LOG").isPresent());
// check records.
Actions actions = mergingReportBuilder.getActionRecorder().build();
XmlElement xmlElement = xmlDocument.getByTypeAndKey(ManifestModel.NodeTypes.USES_PERMISSION,
"android.permission.WRITE_EXTERNAL_STORAGE").get();
ImmutableList<Actions.NodeRecord> nodeRecords = actions
.getNodeRecords(XmlNode.NodeKey.fromXml(xmlElement.getXml()));
assertEquals(1, nodeRecords.size());
assertEquals(nodeRecords.iterator().next().mReason,
"com.example.lib3 has a targetSdkVersion < 4");
}
/**
* Test that multiple intent-filters with the same key and no override are not merged or
* discarded.
*/
public void testMultipleIntentFilter_sameKey_noLibraryDeclaration()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"myspecialdeeplinkscheme\"/>\n"
+ " <data android:host=\"home\"/>\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <activity android:name=\"activityOne\" />\n"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
List<XmlElement> allIntentFilters = getAllElementsOfType(xmlDocument,
ManifestModel.NodeTypes.INTENT_FILTER);
assertEquals(2, allIntentFilters.size());
assertEquals(allIntentFilters.get(0).getId(), allIntentFilters.get(1).getId());
}
/**
* Test that multiple intent-filters with the same key and no override are not merged or
* discarded.
*/
public void testMultipleIntentFilter_sameKey_noOverride()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"myspecialdeeplinkscheme\"/>\n"
+ " <data android:host=\"home\"/>\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.SEARCH\" />\n"
+ " </intent-filter>\n"
+ " </activity>"
+ " </application>"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
List<XmlElement> allIntentFilters = getAllElementsOfType(xmlDocument,
ManifestModel.NodeTypes.INTENT_FILTER);
assertEquals(3, allIntentFilters.size());
}
/**
* Test that multiple intent-filters with the same key and no override are not merged or
* discarded.
*/
public void testMultipleIntentFilter_sameKey_sameOverride()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"myspecialdeeplinkscheme\"/>\n"
+ " <data android:host=\"home\"/>\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.SEARCH\" />\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>"
+ " </application>"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
List<XmlElement> allIntentFilters = getAllElementsOfType(xmlDocument,
ManifestModel.NodeTypes.INTENT_FILTER);
// the second intent-filter of the library should not have been merged in.
assertEquals(3, allIntentFilters.size());
}
/**
* Test that multiple intent-filters with the same key and no override are not merged or
* discarded.
*/
public void testMultipleIntentFilter_sameKey_differentOverride()
throws ParserConfigurationException, SAXException, IOException {
String main = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"myspecialdeeplinkscheme\"/>\n"
+ " <data android:host=\"home\"/>\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.SEARCH\" />\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.bar.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>"
+ " </application>"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
List<XmlElement> allIntentFilters = getAllElementsOfType(xmlDocument,
ManifestModel.NodeTypes.INTENT_FILTER);
// all intent-filters should have been merged.
assertEquals(4, allIntentFilters.size());
}
/**
* Test that multiple intent-filters with the same key and no override are not merged or
* discarded.
*/
public void testMultipleIntentFilter_sameKey_removal()
throws ParserConfigurationException, SAXException, IOException {
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>\n"
+ " <activity android:name=\"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"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.SEARCH\" />\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.bar.com\"/>\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>"
+ " </application>"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
List<XmlElement> allIntentFilters = getAllElementsOfType(xmlDocument,
ManifestModel.NodeTypes.INTENT_FILTER);
// the cleaner is not removed the "remove" node so we should have 2.
assertEquals(2, allIntentFilters.size());
}
public void testMultipleIntentFilter_sameKey_removalAll()
throws ParserConfigurationException, SAXException, IOException {
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>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter tools:node=\"removeAll\"/>\n"
+ " </activity>\n"
+ " </application>"
+ "\n"
+ "</manifest>";
String library = ""
+ "<manifest\n"
+ " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:acme=\"http://acme.org/schemas\"\n"
+ " package=\"com.example.lib3\">\n"
+ "\n"
+ " <application>\n"
+ " <activity android:name=\"activityOne\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.SEARCH\" />\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.bar.com\"/>\n"
+ " </intent-filter>\n"
+ " <intent-filter>\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"
+ " <data android:scheme=\"https\"/>\n"
+ " <data android:host=\"www.foo.com\"/>\n"
+ " </intent-filter>\n"
+ " </activity>"
+ " </application>"
+ " <uses-sdk android:targetSdkVersion=\"3\"/>\n"
+ "\n"
+ "</manifest>";
XmlDocument mainDocument = TestUtils.xmlDocumentFromString(
TestUtils.sourceFile(getClass(), "main"), main);
XmlDocument libraryDocument = TestUtils.xmlLibraryFromString(
TestUtils.sourceFile(getClass(), "library"), library);
MergingReport.Builder mergingReportBuilder = new MergingReport.Builder(mLogger);
Optional<XmlDocument> mergedDocument =
mainDocument.merge(libraryDocument, mergingReportBuilder);
assertTrue(mergedDocument.isPresent());
XmlDocument xmlDocument = mergedDocument.get();
List<XmlElement> allIntentFilters = getAllElementsOfType(xmlDocument,
ManifestModel.NodeTypes.INTENT_FILTER);
// since the cleaner has not run, there is one intent-filter with the removeAll annotation.
assertEquals(1, allIntentFilters.size());
}
private static List<XmlElement> getAllElementsOfType(
XmlDocument xmlDocument,
ManifestModel.NodeTypes nodeType) {
ImmutableList.Builder<XmlElement> listBuilder = ImmutableList.builder();
getAllElementsOfType(xmlDocument.getRootNode(), nodeType, listBuilder);
return listBuilder.build();
}
private static void getAllElementsOfType(XmlElement element,
ManifestModel.NodeTypes nodeType,
ImmutableList.Builder<XmlElement> allElementsBuilder) {
for (XmlElement xmlElement : element.getMergeableElements()) {
if (xmlElement.isA(nodeType)) {
allElementsBuilder.add(xmlElement);
} else {
getAllElementsOfType(xmlElement, nodeType, allElementsBuilder);
}
}
}
private static Element validate(String xml)
throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
dBuilder.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException e) throws SAXException {
}
@Override
public void error(SAXParseException e) throws SAXException {
fail(e.getMessage());
}
@Override
public void fatalError(SAXParseException e) throws SAXException {
fail(e.getMessage());
}
});
Document validated = dBuilder.parse(
new InputSource(new StringReader(xml)));
return (Element) validated.getChildNodes().item(0);
}
}