/*
* Copyright 2012-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.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import com.facebook.buck.apple.xcode.xcodeproj.PBXBuildFile;
import com.facebook.buck.apple.xcode.xcodeproj.PBXBuildPhase;
import com.facebook.buck.apple.xcode.xcodeproj.PBXCopyFilesBuildPhase;
import com.facebook.buck.apple.xcode.xcodeproj.PBXFileReference;
import com.facebook.buck.apple.xcode.xcodeproj.PBXFrameworksBuildPhase;
import com.facebook.buck.apple.xcode.xcodeproj.PBXProject;
import com.facebook.buck.apple.xcode.xcodeproj.PBXReference;
import com.facebook.buck.apple.xcode.xcodeproj.PBXTarget;
import com.facebook.buck.apple.xcode.xcodeproj.XCBuildConfiguration;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.rules.AbstractDescriptionArg;
import com.facebook.buck.rules.PathSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Optional;
public final class ProjectGeneratorTestUtils {
/** Utility class should not be instantiated. */
private ProjectGeneratorTestUtils() {}
public static <T extends AbstractDescriptionArg> T populateArgWithDefaults(T arg) {
for (Field field : arg.getClass().getFields()) {
Object value;
if (field.getType().isAssignableFrom(ImmutableSortedSet.class)) {
value = ImmutableSortedSet.of();
} else if (field.getType().isAssignableFrom(ImmutableList.class)) {
value = ImmutableList.of();
} else if (field.getType().isAssignableFrom(ImmutableMap.class)) {
value = ImmutableMap.of();
} else if (field.getType().isAssignableFrom(Optional.class)) {
value = Optional.empty();
} else if (field.getType().isAssignableFrom(String.class)) {
value = "";
} else if (field.getType().isAssignableFrom(Path.class)) {
value = Paths.get("");
} else if (field.getType().isAssignableFrom(SourcePath.class)) {
value = new PathSourcePath(new FakeProjectFilesystem(), Paths.get(""));
} else if (field.getType().isPrimitive()) {
// do nothing, these are initialized with a zero value
continue;
} else {
// user should provide
continue;
}
try {
field.set(arg, value);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return arg;
}
public static PBXTarget assertTargetExistsAndReturnTarget(
PBXProject generatedProject, String name) {
PBXTarget target = getTargetByName(generatedProject, name);
assertNotNull("No generated target with name: " + name, target);
return target;
}
private static PBXTarget getTargetByName(PBXProject generatedProject, String name) {
Preconditions.checkNotNull(name);
for (PBXTarget target : generatedProject.getTargets()) {
if (target.getName().equals(name)) {
return target;
}
}
return null;
}
public static void assertTargetExists(ProjectGenerator generator, String name) {
assertNotNull(
"No generated target with name: " + name,
getTargetByName(generator.getGeneratedProject(), name));
}
public static void assertTargetDoesNotExists(ProjectGenerator generator, String name) {
assertNull(
"There is generated target with name: " + name,
getTargetByName(generator.getGeneratedProject(), name));
}
public static void assertHasSingletonFrameworksPhaseWithFrameworkEntries(
PBXTarget target, ImmutableList<String> frameworks) {
assertHasSingletonPhaseWithEntries(target, PBXFrameworksBuildPhase.class, frameworks);
}
public static void assertHasSingletonCopyFilesPhaseWithFileEntries(
PBXTarget target, ImmutableList<String> files) {
assertHasSingletonPhaseWithEntries(target, PBXCopyFilesBuildPhase.class, files);
}
public static <T extends PBXBuildPhase> void assertHasSingletonPhaseWithEntries(
PBXTarget target, final Class<T> cls, ImmutableList<String> entries) {
PBXBuildPhase buildPhase = getSingletonPhaseByType(target, cls);
assertThat(
"Phase should have right number of entries",
buildPhase.getFiles(),
hasSize(entries.size()));
for (PBXBuildFile file : buildPhase.getFiles()) {
PBXReference.SourceTree sourceTree = file.getFileRef().getSourceTree();
switch (sourceTree) {
case GROUP:
fail("Should not emit entries with sourceTree <group>");
break;
case ABSOLUTE:
fail("Should not emit entries with sourceTree <absolute>");
break;
// $CASES-OMITTED$
default:
String serialized = "$" + sourceTree + "/" + file.getFileRef().getPath();
assertThat(
"Source tree prefixed file references should exist in list of expected entries.",
entries,
hasItem(serialized));
break;
}
}
}
public static <T extends PBXBuildPhase> T getSingletonPhaseByType(
PBXTarget target, final Class<T> cls) {
Iterable<PBXBuildPhase> buildPhases =
Iterables.filter(target.getBuildPhases(), cls::isInstance);
assertEquals("Build phase should be singleton", 1, Iterables.size(buildPhases));
@SuppressWarnings("unchecked")
T element = (T) Iterables.getOnlyElement(buildPhases);
return element;
}
public static ImmutableMap<String, String> getBuildSettings(
ProjectFilesystem projectFilesystem,
BuildTarget buildTarget,
PBXTarget target,
String config) {
XCBuildConfiguration configuration =
target.getBuildConfigurationList().getBuildConfigurationsByName().asMap().get(config);
assertEquals(configuration.getBuildSettings().count(), 0);
PBXFileReference xcconfigReference = configuration.getBaseConfigurationReference();
Path xcconfigPath = buildTarget.getBasePath().resolve(xcconfigReference.getPath());
String contents = projectFilesystem.readFileIfItExists(xcconfigPath).get();
// Use a HashMap to allow for duplicate keys.
HashMap<String, String> builder = new HashMap<String, String>();
for (String line : contents.split("\n")) {
String[] parts = line.split(" = ");
builder.put(parts[0], parts[1]);
}
return ImmutableMap.copyOf(builder);
}
}