/*
* Copyright 2014-present Facebook, Inc.
*
* 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.facebook.buck.apple.project_generator;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import com.facebook.buck.apple.SchemeActionType;
import com.facebook.buck.apple.xcode.XCScheme;
import com.facebook.buck.apple.xcode.xcodeproj.PBXFileReference;
import com.facebook.buck.apple.xcode.xcodeproj.PBXNativeTarget;
import com.facebook.buck.apple.xcode.xcodeproj.PBXReference;
import com.facebook.buck.apple.xcode.xcodeproj.PBXTarget;
import com.facebook.buck.apple.xcode.xcodeproj.ProductType;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.timing.SettableFakeClock;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SchemeGeneratorTest {
private SettableFakeClock clock;
private ProjectFilesystem projectFilesystem;
@Before
public void setUp() throws IOException {
clock = new SettableFakeClock(0, 0);
projectFilesystem = new FakeProjectFilesystem(clock);
}
@Test
public void schemeWithMultipleTargetsBuildsInCorrectOrder() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget leftTarget = new PBXNativeTarget("leftRule");
leftTarget.setGlobalID("leftGID");
leftTarget.setProductReference(
new PBXFileReference(
"left.a", "left.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
leftTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget rightTarget = new PBXNativeTarget("rightRule");
rightTarget.setGlobalID("rightGID");
rightTarget.setProductReference(
new PBXFileReference(
"right.a", "right.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rightTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget childTarget = new PBXNativeTarget("childRule");
childTarget.setGlobalID("childGID");
childTarget.setProductReference(
new PBXFileReference(
"child.a", "child.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
childTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(leftTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(rightTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(childTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(childTarget),
ImmutableSet.of(rootTarget, leftTarget, rightTarget, childTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
String schemeXml = projectFilesystem.readFileIfItExists(schemePath).get();
System.out.println(schemeXml);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
XPathExpression expr = xpath.compile("//BuildAction//BuildableReference/@BlueprintIdentifier");
NodeList nodes = (NodeList) expr.evaluate(scheme, XPathConstants.NODESET);
List<String> expectedOrdering = ImmutableList.of("rootGID", "leftGID", "rightGID", "childGID");
List<String> actualOrdering = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); i++) {
actualOrdering.add(nodes.item(i).getNodeValue());
}
assertThat(actualOrdering, equalTo(expectedOrdering));
}
@Test
public void schemeBuildsAndTestsAppleTestTargets() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget testDepTarget = new PBXNativeTarget("testDep");
testDepTarget.setGlobalID("testDepGID");
testDepTarget.setProductReference(
new PBXFileReference(
"libDep.a", "libDep.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
testDepTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget testLibraryTarget = new PBXNativeTarget("testLibrary");
testLibraryTarget.setGlobalID("testLibraryGID");
testLibraryTarget.setProductReference(
new PBXFileReference(
"lib.a", "lib.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
testLibraryTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget testTarget = new PBXNativeTarget("test");
testTarget.setGlobalID("testGID");
testTarget.setProductReference(
new PBXFileReference(
"test.xctest",
"test.xctest",
PBXReference.SourceTree.BUILT_PRODUCTS_DIR,
Optional.empty()));
testTarget.setProductType(ProductType.UNIT_TEST);
PBXTarget rootTarget = new PBXNativeTarget("root");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path projectPath = Paths.get("foo/test.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(testTarget, projectPath);
targetToProjectPathMapBuilder.put(testDepTarget, projectPath);
targetToProjectPathMapBuilder.put(testLibraryTarget, projectPath);
targetToProjectPathMapBuilder.put(rootTarget, projectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(testDepTarget, testTarget),
ImmutableSet.of(testTarget),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
String schemeXml = projectFilesystem.readFileIfItExists(schemePath).get();
System.out.println(schemeXml);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath buildXpath = xpathFactory.newXPath();
XPathExpression buildExpr =
buildXpath.compile("//BuildAction//BuildableReference/@BlueprintIdentifier");
NodeList buildNodes = (NodeList) buildExpr.evaluate(scheme, XPathConstants.NODESET);
List<String> expectedBuildOrdering = ImmutableList.of("rootGID", "testDepGID", "testGID");
List<String> actualBuildOrdering = new ArrayList<>();
for (int i = 0; i < buildNodes.getLength(); i++) {
actualBuildOrdering.add(buildNodes.item(i).getNodeValue());
}
assertThat(actualBuildOrdering, equalTo(expectedBuildOrdering));
XPath textXpath = xpathFactory.newXPath();
XPathExpression testExpr =
textXpath.compile(
"//TestAction//TestableReference/BuildableReference/@BlueprintIdentifier");
NodeList testNodes = (NodeList) testExpr.evaluate(scheme, XPathConstants.NODESET);
List<String> expectedTestOrdering = ImmutableList.of("testGID");
List<String> actualTestOrdering = new ArrayList<>();
for (int i = 0; i < testNodes.getLength(); i++) {
actualTestOrdering.add(testNodes.item(i).getNodeValue());
}
assertThat(actualTestOrdering, equalTo(expectedTestOrdering));
}
@Test
public void schemeIncludesAllExpectedActions() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget testTarget = new PBXNativeTarget("testRule");
testTarget.setGlobalID("testGID");
testTarget.setProductReference(
new PBXFileReference(
"test.a", "test.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
testTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget testBundleTarget = new PBXNativeTarget("testBundleRule");
testBundleTarget.setGlobalID("testBundleGID");
testBundleTarget.setProductReference(
new PBXFileReference(
"test.xctest",
"test.xctest",
PBXReference.SourceTree.BUILT_PRODUCTS_DIR,
Optional.empty()));
testBundleTarget.setProductType(ProductType.UNIT_TEST);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(testTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(testBundleTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(testBundleTarget),
ImmutableSet.of(testBundleTarget),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
String schemeXml = projectFilesystem.readFileIfItExists(schemePath).get();
System.out.println(schemeXml);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath buildActionXpath = xpathFactory.newXPath();
XPathExpression buildActionExpr =
buildActionXpath.compile("//BuildAction//BuildableReference/@BlueprintIdentifier");
NodeList buildActionNodes = (NodeList) buildActionExpr.evaluate(scheme, XPathConstants.NODESET);
List<String> expectedOrdering = ImmutableList.of("rootGID", "testBundleGID");
List<String> actualOrdering = new ArrayList<>();
for (int i = 0; i < buildActionNodes.getLength(); i++) {
actualOrdering.add(buildActionNodes.item(i).getNodeValue());
}
assertThat(actualOrdering, equalTo(expectedOrdering));
XPath testActionXpath = xpathFactory.newXPath();
XPathExpression testActionExpr =
testActionXpath.compile("//TestAction//BuildableReference/@BlueprintIdentifier");
String testActionBlueprintIdentifier =
(String) testActionExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(testActionBlueprintIdentifier, equalTo("testBundleGID"));
XPath launchActionXpath = xpathFactory.newXPath();
XPathExpression launchActionExpr =
launchActionXpath.compile("//LaunchAction//BuildableReference/@BlueprintIdentifier");
String launchActionBlueprintIdentifier =
(String) launchActionExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(launchActionBlueprintIdentifier, equalTo("rootGID"));
XPath profileActionXpath = xpathFactory.newXPath();
XPathExpression profileActionExpr =
profileActionXpath.compile("//ProfileAction//BuildableReference/@BlueprintIdentifier");
String profileActionBlueprintIdentifier =
(String) profileActionExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(profileActionBlueprintIdentifier, equalTo("rootGID"));
}
@Test
public void buildableReferenceShouldHaveExpectedProperties() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath buildableReferenceXPath = xpathFactory.newXPath();
XPathExpression buildableReferenceExpr =
buildableReferenceXPath.compile("//BuildableReference");
NodeList buildableReferences =
(NodeList) buildableReferenceExpr.evaluate(scheme, XPathConstants.NODESET);
assertThat(buildableReferences.getLength(), greaterThan(0));
for (int i = 0; i < buildableReferences.getLength(); i++) {
NamedNodeMap attributes = buildableReferences.item(i).getAttributes();
assertThat(attributes, notNullValue());
assertThat(attributes.getNamedItem("BlueprintIdentifier"), notNullValue());
assertThat(attributes.getNamedItem("BuildableIdentifier"), notNullValue());
assertThat(attributes.getNamedItem("ReferencedContainer"), notNullValue());
assertThat(attributes.getNamedItem("BlueprintName"), notNullValue());
assertThat(attributes.getNamedItem("BuildableName"), notNullValue());
}
}
@Test
public void allActionsShouldBePresentInSchemeWithDefaultBuildConfigurations() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath schemeChildrenXPath = xpathFactory.newXPath();
XPathExpression schemeChildrenExpr = schemeChildrenXPath.compile("/Scheme/node()");
NodeList actions = (NodeList) schemeChildrenExpr.evaluate(scheme, XPathConstants.NODESET);
assertThat(actions.getLength(), equalTo(6));
Node buildAction = actions.item(0);
assertThat(buildAction.getNodeName(), equalTo("BuildAction"));
assertThat(buildAction.getAttributes().getNamedItem("buildConfiguration"), nullValue());
Node testAction = actions.item(1);
assertThat(testAction.getNodeName(), equalTo("TestAction"));
assertThat(
testAction.getAttributes().getNamedItem("buildConfiguration").getNodeValue(),
equalTo("Debug"));
Node launchAction = actions.item(2);
assertThat(launchAction.getNodeName(), equalTo("LaunchAction"));
assertThat(
launchAction.getAttributes().getNamedItem("buildConfiguration").getNodeValue(),
equalTo("Debug"));
Node profileAction = actions.item(3);
assertThat(profileAction.getNodeName(), equalTo("ProfileAction"));
assertThat(
profileAction.getAttributes().getNamedItem("buildConfiguration").getNodeValue(),
equalTo("Release"));
Node analyzeAction = actions.item(4);
assertThat(analyzeAction.getNodeName(), equalTo("AnalyzeAction"));
assertThat(
analyzeAction.getAttributes().getNamedItem("buildConfiguration").getNodeValue(),
equalTo("Debug"));
Node archiveAction = actions.item(5);
assertThat(archiveAction.getNodeName(), equalTo("ArchiveAction"));
assertThat(
archiveAction.getAttributes().getNamedItem("buildConfiguration").getNodeValue(),
equalTo("Release"));
}
@Test
public void schemeIsRewrittenIfContentsHaveChanged() throws IOException {
{
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
clock.setCurrentTimeMillis(49152);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
assertThat(
projectFilesystem.getLastModifiedTime(schemePath), equalTo(FileTime.fromMillis(49152L)));
}
{
PBXTarget rootTarget = new PBXNativeTarget("rootRule2");
rootTarget.setGlobalID("root2GID");
rootTarget.setProductReference(
new PBXFileReference(
"root2.a", "root2.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
clock.setCurrentTimeMillis(64738);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
ImmutableMap.of(rootTarget, pbxprojectPath),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
assertThat(
projectFilesystem.getLastModifiedTime(schemePath), equalTo(FileTime.fromMillis(64738L)));
}
}
@Test
public void schemeIsNotRewrittenIfContentsHaveNotChanged() throws IOException {
{
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
clock.setCurrentTimeMillis(49152);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
ImmutableMap.of(rootTarget, pbxprojectPath),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
assertThat(
projectFilesystem.getLastModifiedTime(schemePath), equalTo(FileTime.fromMillis(49152L)));
}
{
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
clock.setCurrentTimeMillis(64738);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
ImmutableMap.of(rootTarget, pbxprojectPath),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
assertThat(
projectFilesystem.getLastModifiedTime(schemePath), equalTo(FileTime.fromMillis(49152L)));
}
}
@Test
public void schemeWithNoPrimaryRuleCanIncludeTests() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget testLibraryTarget = new PBXNativeTarget("testLibrary");
testLibraryTarget.setGlobalID("testLibraryGID");
testLibraryTarget.setProductReference(
new PBXFileReference(
"lib.a", "lib.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
testLibraryTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget testTarget = new PBXNativeTarget("testRule");
testTarget.setGlobalID("testGID");
testTarget.setProductReference(
new PBXFileReference(
"test.a", "test.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
testTarget.setProductType(ProductType.STATIC_LIBRARY);
PBXTarget testBundleTarget = new PBXNativeTarget("testBundleRule");
testBundleTarget.setGlobalID("testBundleGID");
testBundleTarget.setProductReference(
new PBXFileReference(
"test.xctest",
"test.xctest",
PBXReference.SourceTree.BUILT_PRODUCTS_DIR,
Optional.empty()));
testBundleTarget.setProductType(ProductType.UNIT_TEST);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(testLibraryTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(testTarget, pbxprojectPath);
targetToProjectPathMapBuilder.put(testBundleTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.empty(),
ImmutableSet.of(),
ImmutableSet.of(testBundleTarget),
ImmutableSet.of(testBundleTarget),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
String schemeXml = projectFilesystem.readFileIfItExists(schemePath).get();
System.out.println(schemeXml);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath buildActionXpath = xpathFactory.newXPath();
XPathExpression buildActionExpr =
buildActionXpath.compile("//BuildAction//BuildableReference/@BlueprintIdentifier");
NodeList buildActionNodes = (NodeList) buildActionExpr.evaluate(scheme, XPathConstants.NODESET);
List<String> expectedOrdering = ImmutableList.of("testBundleGID");
List<String> actualOrdering = new ArrayList<>();
for (int i = 0; i < buildActionNodes.getLength(); i++) {
actualOrdering.add(buildActionNodes.item(i).getNodeValue());
}
assertThat(actualOrdering, equalTo(expectedOrdering));
XPath testActionXpath = xpathFactory.newXPath();
XPathExpression testActionExpr =
testActionXpath.compile("//TestAction//BuildableReference/@BlueprintIdentifier");
String testActionBlueprintIdentifier =
(String) testActionExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(testActionBlueprintIdentifier, equalTo("testBundleGID"));
XPath launchActionXpath = xpathFactory.newXPath();
XPathExpression launchActionExpr =
launchActionXpath.compile("//LaunchAction//BuildableReference/@BlueprintIdentifier");
String launchActionBlueprintIdentifier =
(String) launchActionExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(launchActionBlueprintIdentifier, equalTo(""));
XPath launchActionBuildConfigurationXpath = xpathFactory.newXPath();
XPathExpression launchActionBuildConfigurationExpr =
launchActionBuildConfigurationXpath.compile("//LaunchAction//@buildConfiguration");
String launchActionBuildConfigurationBlueprintIdentifier =
(String) launchActionBuildConfigurationExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(launchActionBuildConfigurationBlueprintIdentifier, equalTo("Debug"));
XPath profileActionXpath = xpathFactory.newXPath();
XPathExpression profileActionExpr =
profileActionXpath.compile("//ProfileAction//BuildableReference/@BlueprintIdentifier");
String profileActionBlueprintIdentifier =
(String) profileActionExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(profileActionBlueprintIdentifier, equalTo(""));
XPath profileActionBuildConfigurationXpath = xpathFactory.newXPath();
XPathExpression profileActionBuildConfigurationExpr =
profileActionBuildConfigurationXpath.compile("//ProfileAction//@buildConfiguration");
String profileActionBuildConfigurationBlueprintIdentifier =
(String) profileActionBuildConfigurationExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(profileActionBuildConfigurationBlueprintIdentifier, equalTo("Release"));
XPath analyzeActionBuildConfigurationXpath = xpathFactory.newXPath();
XPathExpression analyzeActionBuildConfigurationExpr =
analyzeActionBuildConfigurationXpath.compile("//AnalyzeAction//@buildConfiguration");
String analyzeActionBuildConfigurationBlueprintIdentifier =
(String) analyzeActionBuildConfigurationExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(analyzeActionBuildConfigurationBlueprintIdentifier, equalTo("Debug"));
XPath archiveActionBuildConfigurationXpath = xpathFactory.newXPath();
XPathExpression archiveActionBuildConfigurationExpr =
archiveActionBuildConfigurationXpath.compile("//ArchiveAction//@buildConfiguration");
String archiveActionBuildConfigurationBlueprintIdentifier =
(String) archiveActionBuildConfigurationExpr.evaluate(scheme, XPathConstants.STRING);
assertThat(archiveActionBuildConfigurationBlueprintIdentifier, equalTo("Release"));
}
@Test
public void launchActionShouldNotContainRemoteRunnableWhenNotProvided() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath remoteRunnableLaunchActionXPath = xpathFactory.newXPath();
XPathExpression remoteRunnableLaunchActionExpr =
remoteRunnableLaunchActionXPath.compile("//LaunchAction/RemoteRunnable");
NodeList remoteRunnables =
(NodeList) remoteRunnableLaunchActionExpr.evaluate(scheme, XPathConstants.NODESET);
assertThat(remoteRunnables.getLength(), equalTo(0));
}
@Test
public void launchActionShouldContainRemoteRunnableWhenProvided() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
false /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.of("/RemoteApp") /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath remoteRunnableLaunchActionXPath = xpathFactory.newXPath();
XPathExpression remoteRunnableLaunchActionExpr =
remoteRunnableLaunchActionXPath.compile("//LaunchAction/RemoteRunnable");
NodeList remoteRunnables =
(NodeList) remoteRunnableLaunchActionExpr.evaluate(scheme, XPathConstants.NODESET);
assertThat(remoteRunnables.getLength(), equalTo(1));
Node remoteRunnable = remoteRunnables.item(0);
assertThat(
remoteRunnable.getAttributes().getNamedItem("runnableDebuggingMode").getNodeValue(),
equalTo("2"));
assertThat(
remoteRunnable.getAttributes().getNamedItem("BundleIdentifier").getNodeValue(),
equalTo("com.apple.springboard"));
assertThat(
remoteRunnable.getAttributes().getNamedItem("RemotePath").getNodeValue(),
equalTo("/RemoteApp"));
XPath buildXpath = xpathFactory.newXPath();
XPathExpression buildExpr =
buildXpath.compile("//LaunchAction//BuildableReference/@BlueprintIdentifier");
NodeList buildNodes = (NodeList) buildExpr.evaluate(scheme, XPathConstants.NODESET);
// Make sure both copies of the BuildableReference are present.
assertThat(buildNodes.getLength(), equalTo(2));
assertThat(buildNodes.item(0).getNodeValue(), equalTo("rootGID"));
assertThat(buildNodes.item(1).getNodeValue(), equalTo("rootGID"));
}
@Test
public void enablingParallelizeBuild() throws Exception {
ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
PBXTarget rootTarget = new PBXNativeTarget("rootRule");
rootTarget.setGlobalID("rootGID");
rootTarget.setProductReference(
new PBXFileReference(
"root.a", "root.a", PBXReference.SourceTree.BUILT_PRODUCTS_DIR, Optional.empty()));
rootTarget.setProductType(ProductType.STATIC_LIBRARY);
Path pbxprojectPath = Paths.get("foo/Foo.xcodeproj/project.pbxproj");
targetToProjectPathMapBuilder.put(rootTarget, pbxprojectPath);
SchemeGenerator schemeGenerator =
new SchemeGenerator(
projectFilesystem,
Optional.of(rootTarget),
ImmutableSet.of(rootTarget),
ImmutableSet.of(),
ImmutableSet.of(),
"TestScheme",
Paths.get("_gen/Foo.xcworkspace/scshareddata/xcshemes"),
true /* parallelizeBuild */,
Optional.empty() /* runnablePath */,
Optional.empty() /* remoteRunnablePath */,
SchemeActionType.DEFAULT_CONFIG_NAMES,
targetToProjectPathMapBuilder.build(),
XCScheme.LaunchAction.LaunchStyle.AUTO);
Path schemePath = schemeGenerator.writeScheme();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document scheme = dBuilder.parse(projectFilesystem.newFileInputStream(schemePath));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath buildActionXpath = xpathFactory.newXPath();
XPathExpression buildActionExpr = buildActionXpath.compile("//BuildAction");
NodeList buildActionNodes = (NodeList) buildActionExpr.evaluate(scheme, XPathConstants.NODESET);
assertThat(buildActionNodes.getLength(), is(1));
Node buildActionNode = buildActionNodes.item(0);
assertThat(
buildActionNode.getAttributes().getNamedItem("buildImplicitDependencies").getNodeValue(),
equalTo("YES"));
assertThat(
buildActionNode.getAttributes().getNamedItem("parallelizeBuildables").getNodeValue(),
equalTo("YES"));
}
}