blob: 8c7e41ae6964e11a29b16c79be531797be7a25f1 [file] [log] [blame]
/*
* 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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import com.facebook.buck.apple.CompilationDatabase.JsonSerializableDatabaseEntry;
import com.facebook.buck.apple.clang.HeaderMap;
import com.facebook.buck.testutil.MoreAsserts;
import com.facebook.buck.testutil.integration.DebuggableTemporaryFolder;
import com.facebook.buck.testutil.integration.ProjectWorkspace;
import com.facebook.buck.testutil.integration.TestDataHelper;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CompilationDatabaseIntegrationTest {
/** This is the value of xcode_developer_dir in the .buckconfig for this test. */
private static final Path XCODE_DEVELOPER_DIR = Paths.get("xcode-developer-dir");
@Rule
public DebuggableTemporaryFolder tmp = new DebuggableTemporaryFolder();
private ProjectWorkspace workspace;
@Before
public void setupWorkspace() throws IOException {
workspace = TestDataHelper.createProjectWorkspaceForScenario(
this, "ios-project", tmp);
workspace.setUp();
Path platforms = workspace.getPath("xcode-developer-dir/Platforms");
Path sdk = platforms.resolve("iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk");
Files.createSymbolicLink(sdk.getParent().resolve("iPhoneOS8.0.sdk"), sdk);
sdk = platforms.resolve("iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk");
Files.createSymbolicLink(sdk.getParent().resolve("iPhoneSimulator8.0.sdk"), sdk);
}
@Test
public void testBuildHeadersFlavorDirectly() throws IOException {
// build an intermediate #headers rule.
workspace.runBuckBuild("//Libraries/EXExample:EXExample#headers").assertSuccess();
// Verify the contents of the headers directory.
String pathToHeaders =
"buck-out/bin/Libraries/EXExample/__EXExample#headers_public_headers__";
File headersDirectory = workspace.getFile(pathToHeaders);
assertTrue(
"public header should be available in " + headersDirectory + ".",
new File(headersDirectory, "EXExample/EXExampleModel.h").exists());
assertFalse(
"non-public header should not be available in " + headersDirectory + ".",
new File(headersDirectory, "EXExample/NSString+Palindrome.h").exists());
}
@Test
@SuppressWarnings("PMD.LooseCoupling") // ArrayList.class
public void testCreateCompilationDatabaseForAppleLibraryWithNoDeps() throws IOException {
// buck build the #compilation-database.
File compilationDatabase = workspace.buildAndReturnOutput(
"//Libraries/EXExample:EXExample#compilation-database");
assertEquals(
Paths.get("buck-out/gen/Libraries/EXExample/" +
"__EXExample#compilation-database_compilation_database.json"),
tmp.getRootPath().relativize(compilationDatabase.toPath()));
// Parse the compilation_database.json file.
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().
constructCollectionType(ArrayList.class, JsonSerializableDatabaseEntry.class);
List<JsonSerializableDatabaseEntry> entries = mapper.readValue(compilationDatabase, type);
Map<String, JsonSerializableDatabaseEntry> fileToEntry = Maps.newHashMap();
for (JsonSerializableDatabaseEntry entry : entries) {
fileToEntry.put(entry.file, entry);
}
// Verify the entries in the compilation database.
String iquoteArg = tmp.getRootPath().resolve(
"buck-out/bin/Libraries/EXExample/__my_EXExample#compilation-database__.hmap")
.toRealPath()
.toString();
assertFlags(
"Libraries/EXExample/EXExample/EXExampleModel.h",
fileToEntry,
/* additionalFrameworks */ ImmutableList.<String>of(),
/* includes */ ImmutableList.<String>of(),
iquoteArg);
assertFlags(
"Libraries/EXExample/EXExample/EXExampleModel.m",
fileToEntry,
/* additionalFrameworks */ ImmutableList.<String>of(),
/* includes */ ImmutableList.<String>of(),
iquoteArg);
assertFlags(
"Libraries/EXExample/EXExample/EXUser.mm",
fileToEntry,
/* additionalFrameworks */ ImmutableList.<String>of(),
/* includes */ ImmutableList.<String>of(),
iquoteArg);
assertFlags(
"Libraries/EXExample/EXExample/Categories/NSString+Palindrome.h",
fileToEntry,
/* additionalFrameworks */ ImmutableList.<String>of(),
/* includes */ ImmutableList.<String>of(),
iquoteArg);
assertFlags(
"Libraries/EXExample/EXExample/Categories/NSString+Palindrome.m",
fileToEntry,
/* additionalFrameworks */ ImmutableList.<String>of(),
/* includes */ ImmutableList.<String>of(),
iquoteArg);
// Verify the header map specified as the iquote argument.
HeaderMap headerMap = HeaderMap.loadFromFile(workspace.getFile(iquoteArg));
assertEquals(
tmp.getRootPath().resolve("Libraries/EXExample/EXExample/EXExampleModel.h")
.toRealPath(),
Paths.get(headerMap.lookup("EXExampleModel.h")));
assertEquals(
tmp.getRootPath().resolve("Libraries/EXExample/EXExample/Categories/NSString+Palindrome.h")
.toRealPath(),
Paths.get(headerMap.lookup("NSString+Palindrome.h")));
}
@Test
@SuppressWarnings("PMD.LooseCoupling") // ArrayList.class
public void testCreateCompilationDatabaseForAppleBinaryWithDeps() throws IOException {
// buck build the #compilation-database.
File compilationDatabase = workspace.buildAndReturnOutput(
"//Apps/Weather:Weather#compilation-database");
assertEquals(
Paths.get("buck-out/gen/Apps/Weather/" +
"__Weather#compilation-database_compilation_database.json"),
tmp.getRootPath().relativize(compilationDatabase.toPath()));
// Parse the compilation_database.json file.
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().
constructCollectionType(ArrayList.class, JsonSerializableDatabaseEntry.class);
List<JsonSerializableDatabaseEntry> entries = mapper.readValue(compilationDatabase, type);
Map<String, JsonSerializableDatabaseEntry> fileToEntry = Maps.newHashMap();
for (JsonSerializableDatabaseEntry entry : entries) {
fileToEntry.put(entry.file, entry);
}
// Verify the entries in the compilation database.
String iquoteArg = tmp.getRootPath().resolve(
"buck-out/bin/Apps/Weather/__my_Weather#compilation-database__.hmap")
.toRealPath()
.toString();
String pathToHeaders = "buck-out/bin/Libraries/EXExample/__EXExample#headers_public_headers__";
assertFlags(
"Apps/Weather/Weather/EXViewController.h",
fileToEntry,
ImmutableList.of("/System/Library/Frameworks/UIKit.framework"),
ImmutableList.of(pathToHeaders),
iquoteArg);
assertFlags(
"Apps/Weather/Weather/EXViewController.m",
fileToEntry,
ImmutableList.of("/System/Library/Frameworks/UIKit.framework"),
ImmutableList.of(pathToHeaders),
iquoteArg);
assertFlags(
"Apps/Weather/Weather/main.m",
fileToEntry,
ImmutableList.of("/System/Library/Frameworks/UIKit.framework"),
ImmutableList.of(pathToHeaders),
iquoteArg);
}
private void assertFlags(
String fileName,
Map<String, JsonSerializableDatabaseEntry> fileToEntry,
Iterable<String> additionalFrameworks,
Iterable<String> includes,
String iquoteArg) throws IOException {
String key = tmp.getRootPath().resolve(fileName).toRealPath().toString();
JsonSerializableDatabaseEntry entry = fileToEntry.get(key);
assertNotNull("There should be an entry for " + key + ".", entry);
String sdkRoot = tmp.getRootPath()
.resolve(XCODE_DEVELOPER_DIR)
.resolve("Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk")
.toRealPath().toString();
String language = "objective-c";
String languageStandard = "-std=gnu99";
if ("Libraries/EXExample/EXExample/EXUser.mm".equals(fileName)) {
language = "objective-c++";
languageStandard = "-std=c++11";
}
List<String> commandArgs = Lists.newArrayList(
"clang",
"-x",
language,
"-arch",
"i386",
"-mios-simulator-version-min=7.0",
"-fmessage-length=0",
"-fdiagnostics-show-note-include-stack",
"-fmacro-backtrace-limit=0",
languageStandard,
"-fpascal-strings",
"-fexceptions",
"-fasm-blocks",
"-fstrict-aliasing",
"-fobjc-abi-version=2",
"-fobjc-legacy-dispatch",
"-O0",
"-g",
"-MMD",
"-fobjc-arc",
"-isysroot",
sdkRoot,
"-F" + sdkRoot + "/System/Library/Frameworks/Foundation.framework");
for (String framework : additionalFrameworks) {
commandArgs.add("-F" + sdkRoot + framework);
}
for (String include : includes) {
commandArgs.add("-I" + tmp.getRootPath().resolve(include).toRealPath());
}
commandArgs.addAll(ImmutableList.of(
"-iquote",
iquoteArg,
"-c",
entry.file));
MoreAsserts.assertIterablesEquals(commandArgs, ImmutableList.copyOf(entry.command.split(" ")));
}
}