| // Copyright 2016 The Tulsi Authors. All rights reserved. |
| // |
| // 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. |
| |
| import XCTest |
| |
| @testable import TulsiGenerator |
| |
| class XcodeProjectGeneratorTests: XCTestCase { |
| static let outputFolderPath = "/dev/null/project" |
| static let projectName = "ProjectName" |
| |
| let outputFolderURL = URL(fileURLWithPath: XcodeProjectGeneratorTests.outputFolderPath) |
| let xcodeProjectPath |
| = "\(XcodeProjectGeneratorTests.outputFolderPath)/\(XcodeProjectGeneratorTests.projectName).xcodeproj" |
| |
| let workspaceRoot = URL(fileURLWithPath: "/workspace") |
| let testTulsiVersion = "9.99.999.9999" |
| |
| let buildTargetLabels = ["//test:MainTarget", "//test/path/to/target:target"].map({ |
| BuildLabel($0) |
| }) |
| let pathFilters = Set<String>(["test", "additional"]) |
| |
| let additionalFilePaths = ["additional/File1", "additional/File2"] |
| |
| let bazelURL = TulsiParameter( |
| value: URL(fileURLWithPath: "/test/dir/testBazel"), |
| source: .explicitlyProvided) |
| |
| let resourceURLs = XcodeProjectGenerator.ResourceSourcePathURLs( |
| buildScript: URL(fileURLWithPath: "/scripts/Build"), |
| cleanScript: URL(fileURLWithPath: "/scripts/Clean"), |
| extraBuildScripts: [URL(fileURLWithPath: "/scripts/Logging")], |
| iOSUIRunnerEntitlements: URL( |
| fileURLWithPath: "/generatedProjectResources/iOSXCTRunner.entitlements"), |
| macOSUIRunnerEntitlements: URL( |
| fileURLWithPath: "/generatedProjectResources/macOSXCTRunner.entitlements"), |
| stubInfoPlist: URL(fileURLWithPath: "/generatedProjectResources/StubInfoPlist.plist"), |
| stubIOSAppExInfoPlistTemplate: URL( |
| fileURLWithPath: "/generatedProjectResources/stubIOSAppExInfoPlist.plist"), |
| stubWatchOS2InfoPlist: URL( |
| fileURLWithPath: "/generatedProjectResources/StubWatchOS2InfoPlist.plist"), |
| stubWatchOS2AppExInfoPlist: URL( |
| fileURLWithPath: "/generatedProjectResources/StubWatchOS2AppExInfoPlist.plist"), |
| bazelWorkspaceFile: URL(fileURLWithPath: "/WORKSPACE"), |
| tulsiPackageFiles: [URL(fileURLWithPath: "/tulsi/tulsi_aspects.bzl")]) |
| |
| var config: TulsiGeneratorConfig! = nil |
| var mockLocalizedMessageLogger: MockLocalizedMessageLogger! = nil |
| var mockFileManager: MockFileManager! = nil |
| var mockExtractor: MockWorkspaceInfoExtractor! = nil |
| var generator: XcodeProjectGenerator! = nil |
| |
| var writtenFiles = Set<String>() |
| |
| override func setUp() { |
| super.setUp() |
| mockLocalizedMessageLogger = MockLocalizedMessageLogger() |
| mockFileManager = MockFileManager() |
| mockExtractor = MockWorkspaceInfoExtractor() |
| writtenFiles.removeAll() |
| } |
| |
| func testSuccessfulGeneration() { |
| let ruleEntries = XcodeProjectGeneratorTests.labelToRuleEntryMapForLabels(buildTargetLabels) |
| prepareGenerator(ruleEntries) |
| do { |
| _ = try generator.generateXcodeProjectInFolder(outputFolderURL) |
| mockLocalizedMessageLogger.assertNoErrors() |
| mockLocalizedMessageLogger.assertNoWarnings() |
| |
| XCTAssert(writtenFiles.contains("\(xcodeProjectPath)/project.pbxproj")) |
| XCTAssert( |
| writtenFiles.contains( |
| "\(xcodeProjectPath)/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings")) |
| XCTAssert( |
| writtenFiles.contains( |
| "\(xcodeProjectPath)/project.xcworkspace/xcuserdata/USER.xcuserdatad/WorkspaceSettings.xcsettings" |
| )) |
| XCTAssert( |
| writtenFiles.contains( |
| "\(xcodeProjectPath)/xcshareddata/xcschemes/test-path-to-target-target.xcscheme")) |
| XCTAssert( |
| writtenFiles.contains("\(xcodeProjectPath)/xcshareddata/xcschemes/test-MainTarget.xcscheme") |
| ) |
| |
| let supportScriptsURL = mockFileManager.homeDirectoryForCurrentUser.appendingPathComponent( |
| "Library/Application Support/Tulsi/Scripts", isDirectory: true) |
| XCTAssert(mockFileManager.directoryOperations.contains(supportScriptsURL.path)) |
| |
| let cacheReaderURL = supportScriptsURL.appendingPathComponent( |
| "bazel_cache_reader", |
| isDirectory: false) |
| XCTAssert(mockFileManager.copyOperations.keys.contains(cacheReaderURL.path)) |
| |
| let xcp = "\(xcodeProjectPath)/xcuserdata/USER.xcuserdatad/xcschemes/xcschememanagement.plist" |
| XCTAssert(!mockFileManager.attributesMap.isEmpty) |
| mockFileManager.attributesMap.forEach { (path, attrs) in |
| XCTAssertNotNil(attrs[.modificationDate]) |
| } |
| XCTAssert(mockFileManager.writeOperations.keys.contains(xcp)) |
| } catch let e { |
| XCTFail("Unexpected exception \(e)") |
| } |
| } |
| |
| func testExtensionPlistGeneration() { |
| @discardableResult |
| func addRule( |
| _ labelName: String, |
| type: String, |
| attributes: [String: AnyObject] = [:], |
| weakDependencies: Set<BuildLabel>? = nil, |
| extensions: Set<BuildLabel>? = nil, |
| extensionType: String? = nil, |
| productType: PBXTarget.ProductType? = nil |
| ) -> BuildLabel { |
| let label = BuildLabel(labelName) |
| mockExtractor.labelToRuleEntry[label] = Swift.type(of: self).makeRuleEntry( |
| label, |
| type: type, |
| attributes: attributes, |
| weakDependencies: weakDependencies, |
| extensions: extensions, |
| productType: productType, |
| extensionType: extensionType) |
| return label |
| } |
| |
| let test1 = addRule( |
| "//test:ExtFoo", type: "ios_extension", extensionType: "com.apple.extension-foo", |
| productType: .AppExtension) |
| let test2 = addRule( |
| "//test:ExtBar", type: "ios_extension", extensionType: "com.apple.extension-bar", |
| productType: .AppExtension) |
| addRule( |
| "//test:Application", type: "ios_application", extensions: [test1, test2], |
| productType: .Application) |
| prepareGenerator(mockExtractor.labelToRuleEntry) |
| |
| func assertPlist(withData data: Data, equalTo value: NSDictionary) { |
| let content = try! PropertyListSerialization.propertyList( |
| from: data, options: PropertyListSerialization.ReadOptions.mutableContainers, format: nil) |
| as! NSDictionary |
| XCTAssertEqual(content, value) |
| } |
| |
| do { |
| _ = try generator.generateXcodeProjectInFolder(outputFolderURL) |
| mockLocalizedMessageLogger.assertNoErrors() |
| mockLocalizedMessageLogger.assertNoWarnings() |
| |
| XCTAssert( |
| mockFileManager.writeOperations.keys.contains( |
| "\(xcodeProjectPath)/.tulsi/Resources/Stub_test-ExtFoo.plist")) |
| assertPlist( |
| withData: mockFileManager.writeOperations[ |
| "\(xcodeProjectPath)/.tulsi/Resources/Stub_test-ExtFoo.plist"]!, |
| equalTo: ["NSExtension": ["NSExtensionPointIdentifier": "com.apple.extension-foo"]]) |
| |
| XCTAssert( |
| mockFileManager.writeOperations.keys.contains( |
| "\(xcodeProjectPath)/.tulsi/Resources/Stub_test-ExtBar.plist")) |
| assertPlist( |
| withData: mockFileManager.writeOperations[ |
| "\(xcodeProjectPath)/.tulsi/Resources/Stub_test-ExtBar.plist"]!, |
| equalTo: ["NSExtension": ["NSExtensionPointIdentifier": "com.apple.extension-bar"]]) |
| } catch let e { |
| XCTFail("Unexpected exception \(e)") |
| } |
| } |
| |
| func testUnresolvedLabelsThrows() { |
| let ruleEntries = XcodeProjectGeneratorTests.labelToRuleEntryMapForLabels(buildTargetLabels) |
| prepareGenerator(ruleEntries) |
| mockExtractor.labelToRuleEntry = [:] |
| do { |
| _ = try generator.generateXcodeProjectInFolder(outputFolderURL) |
| XCTFail("Generation succeeded unexpectedly") |
| } catch XcodeProjectGenerator.ProjectGeneratorError.labelResolutionFailed(let missingLabels) { |
| for label in buildTargetLabels { |
| XCTAssert(missingLabels.contains(label), "Expected missing label \(label) not found") |
| } |
| } catch let e { |
| XCTFail("Unexpected exception \(e)") |
| } |
| } |
| |
| func testInvalidPathThrows() { |
| let ruleEntries = XcodeProjectGeneratorTests.labelToRuleEntryMapForLabels(buildTargetLabels) |
| prepareGenerator(ruleEntries) |
| let invalidOutputFolderString = "/dev/null/bazel-build" |
| let invalidOutputFolderURL = URL(fileURLWithPath: invalidOutputFolderString) |
| |
| do { |
| _ = try generator.generateXcodeProjectInFolder(invalidOutputFolderURL) |
| XCTFail("Generation succeeded unexpectedly") |
| } catch XcodeProjectGenerator.ProjectGeneratorError.invalidXcodeProjectPath( |
| let pathFound, |
| let reason) |
| { |
| // Expected failure on path with a /bazel-* directory. |
| XCTAssertEqual(pathFound, invalidOutputFolderString) |
| XCTAssertEqual(reason, "a Bazel generated temp directory (\"/bazel-\")") |
| } catch let e { |
| XCTFail("Unexpected exception \(e)") |
| } |
| } |
| |
| func testTestSuiteSchemeGenerationWithSkylarkUnitTest() { |
| checkTestSuiteSchemeGeneration( |
| "ios_unit_test", |
| testProductType: .UnitTest, |
| testHostAttributeName: "test_host") |
| } |
| |
| func testTestSuiteSchemeGenerationWithSkylarkUITest() { |
| checkTestSuiteSchemeGeneration( |
| "ios_ui_test", |
| testProductType: .UIUnitTest, |
| testHostAttributeName: "test_host") |
| } |
| |
| func checkTestSuiteSchemeGeneration( |
| _ testRuleType: String, |
| testProductType: PBXTarget.ProductType, |
| testHostAttributeName: String |
| ) { |
| @discardableResult |
| func addRule( |
| _ labelName: String, |
| type: String, |
| attributes: [String: AnyObject] = [:], |
| weakDependencies: Set<BuildLabel>? = nil, |
| productType: PBXTarget.ProductType? = nil |
| ) -> BuildLabel { |
| let label = BuildLabel(labelName) |
| mockExtractor.labelToRuleEntry[label] = Swift.type(of: self).makeRuleEntry( |
| label, |
| type: type, |
| attributes: attributes, |
| weakDependencies: weakDependencies, |
| productType: productType) |
| return label |
| } |
| |
| let app = addRule("//test:Application", type: "ios_application", productType: .Application) |
| let test1 = addRule( |
| "//test:TestOne", |
| type: testRuleType, |
| attributes: [testHostAttributeName: app.value as AnyObject], |
| productType: testProductType) |
| let test2 = addRule( |
| "//test:TestTwo", |
| type: testRuleType, |
| attributes: [testHostAttributeName: app.value as AnyObject], |
| productType: testProductType) |
| addRule("//test:UnusedTest", type: testRuleType, productType: testProductType) |
| addRule("//test:TestSuite", type: "test_suite", weakDependencies: Set([test1, test2])) |
| prepareGenerator(mockExtractor.labelToRuleEntry) |
| |
| do { |
| _ = try generator.generateXcodeProjectInFolder(outputFolderURL) |
| mockLocalizedMessageLogger.assertNoErrors() |
| mockLocalizedMessageLogger.assertNoWarnings() |
| |
| XCTAssert(writtenFiles.contains("\(xcodeProjectPath)/project.pbxproj")) |
| XCTAssert( |
| writtenFiles.contains( |
| "\(xcodeProjectPath)/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings")) |
| XCTAssert( |
| writtenFiles.contains( |
| "\(xcodeProjectPath)/project.xcworkspace/xcuserdata/USER.xcuserdatad/WorkspaceSettings.xcsettings" |
| )) |
| XCTAssert( |
| writtenFiles.contains( |
| "\(xcodeProjectPath)/xcshareddata/xcschemes/test-Application.xcscheme")) |
| XCTAssert( |
| writtenFiles.contains("\(xcodeProjectPath)/xcshareddata/xcschemes/test-TestOne.xcscheme")) |
| XCTAssert( |
| writtenFiles.contains("\(xcodeProjectPath)/xcshareddata/xcschemes/test-TestTwo.xcscheme")) |
| XCTAssert( |
| writtenFiles.contains("\(xcodeProjectPath)/xcshareddata/xcschemes/test-UnusedTest.xcscheme") |
| ) |
| XCTAssert( |
| writtenFiles.contains("\(xcodeProjectPath)/xcshareddata/xcschemes/TestSuite_Suite.xcscheme") |
| ) |
| } catch let e { |
| XCTFail("Unexpected exception \(e)") |
| } |
| } |
| |
| func testProjectSDKROOT() { |
| func validate(_ types: [(String, String)], _ expectedSDKROOT: String?, line: UInt = #line) { |
| let rules = types.map { tuple in |
| // Both the platform and osDeploymentTarget must be set in order to create a valid |
| // deploymentTarget for the RuleEntry. |
| XcodeProjectGeneratorTests.makeRuleEntry( |
| BuildLabel(tuple.0), type: tuple.0, platformType: tuple.1, |
| osDeploymentTarget: "this_must_not_be_nil") |
| } |
| let sdkroot = XcodeProjectGenerator.projectSDKROOT(rules) |
| XCTAssertEqual(sdkroot, expectedSDKROOT, line: line) |
| } |
| |
| let iosAppTuple = ("ios_application", "ios") |
| let tvExtensionTuple = ("tvos_extension", "tvos") |
| validate([iosAppTuple], "iphoneos") |
| validate([iosAppTuple, iosAppTuple], "iphoneos") |
| validate([iosAppTuple, tvExtensionTuple], nil) |
| validate([tvExtensionTuple], "appletvos") |
| } |
| |
| // MARK: - Private methods |
| |
| private static func labelToRuleEntryMapForLabels(_ labels: [BuildLabel]) -> [BuildLabel: |
| RuleEntry] |
| { |
| var ret = [BuildLabel: RuleEntry]() |
| for label in labels { |
| ret[label] = makeRuleEntry(label, type: "ios_application", productType: .Application) |
| } |
| return ret |
| } |
| |
| private static func makeRuleEntry( |
| _ label: BuildLabel, |
| type: String, |
| attributes: [String: AnyObject] = [:], |
| artifacts: [BazelFileInfo] = [], |
| sourceFiles: [BazelFileInfo] = [], |
| nonARCSourceFiles: [BazelFileInfo] = [], |
| dependencies: Set<BuildLabel> = Set(), |
| secondaryArtifacts: [BazelFileInfo] = [], |
| weakDependencies: Set<BuildLabel>? = nil, |
| buildFilePath: String? = nil, |
| objcDefines: [String]? = nil, |
| swiftDefines: [String]? = nil, |
| includePaths: [RuleEntry.IncludePath]? = nil, |
| extensions: Set<BuildLabel>? = nil, |
| productType: PBXTarget.ProductType? = nil, |
| extensionType: String? = nil, |
| platformType: String? = nil, |
| osDeploymentTarget: String? = nil |
| ) -> RuleEntry { |
| return RuleEntry( |
| label: label, |
| type: type, |
| attributes: attributes, |
| artifacts: artifacts, |
| sourceFiles: sourceFiles, |
| nonARCSourceFiles: nonARCSourceFiles, |
| dependencies: dependencies, |
| secondaryArtifacts: secondaryArtifacts, |
| weakDependencies: weakDependencies, |
| extensions: extensions, |
| productType: productType, |
| platformType: platformType, |
| osDeploymentTarget: osDeploymentTarget, |
| buildFilePath: buildFilePath, |
| objcDefines: objcDefines, |
| swiftDefines: swiftDefines, |
| includePaths: includePaths, |
| extensionType: extensionType) |
| } |
| |
| private func prepareGenerator(_ ruleEntries: [BuildLabel: RuleEntry]) { |
| let options = TulsiOptionSet() |
| // To avoid creating ~/Library folders and changing UserDefaults during CI testing. |
| config = TulsiGeneratorConfig( |
| projectName: XcodeProjectGeneratorTests.projectName, |
| buildTargetLabels: Array(ruleEntries.keys), |
| pathFilters: pathFilters, |
| additionalFilePaths: additionalFilePaths, |
| options: options, |
| bazelURL: bazelURL) |
| let projectURL = URL(fileURLWithPath: xcodeProjectPath, isDirectory: true) |
| mockFileManager.allowedDirectoryCreates.insert(projectURL.path) |
| |
| let tulsiworkspace = projectURL.appendingPathComponent("tulsi-workspace") |
| mockFileManager.allowedDirectoryCreates.insert(tulsiworkspace.path) |
| |
| let bazelCacheReaderURL = mockFileManager.homeDirectoryForCurrentUser.appendingPathComponent( |
| "Library/Application Support/Tulsi/Scripts", isDirectory: true) |
| mockFileManager.allowedDirectoryCreates.insert(bazelCacheReaderURL.path) |
| |
| let xcshareddata = projectURL.appendingPathComponent("project.xcworkspace/xcshareddata") |
| mockFileManager.allowedDirectoryCreates.insert(xcshareddata.path) |
| |
| let xcuserdata = projectURL.appendingPathComponent( |
| "project.xcworkspace/xcuserdata/USER.xcuserdatad") |
| mockFileManager.allowedDirectoryCreates.insert(xcuserdata.path) |
| |
| let xcschemes = projectURL.appendingPathComponent("xcshareddata/xcschemes") |
| mockFileManager.allowedDirectoryCreates.insert(xcschemes.path) |
| |
| let userXcschemes = projectURL.appendingPathComponent("xcuserdata/USER.xcuserdatad/xcschemes") |
| mockFileManager.allowedDirectoryCreates.insert(userXcschemes.path) |
| |
| let scripts = projectURL.appendingPathComponent(".tulsi/Scripts") |
| mockFileManager.allowedDirectoryCreates.insert(scripts.path) |
| |
| let utils = projectURL.appendingPathComponent(".tulsi/Utils") |
| mockFileManager.allowedDirectoryCreates.insert(utils.path) |
| |
| let resources = projectURL.appendingPathComponent(".tulsi/Resources") |
| mockFileManager.allowedDirectoryCreates.insert(resources.path) |
| |
| let tulsiBazelRoot = projectURL.appendingPathComponent(".tulsi/Bazel") |
| mockFileManager.allowedDirectoryCreates.insert(tulsiBazelRoot.path) |
| |
| let tulsiBazelPackage = projectURL.appendingPathComponent(".tulsi/Bazel/tulsi") |
| mockFileManager.allowedDirectoryCreates.insert(tulsiBazelPackage.path) |
| |
| let mockTemplate = ["NSExtension": ["NSExtensionPointIdentifier": "com.apple.intents-service"]] |
| let templateData = try! PropertyListSerialization.data( |
| fromPropertyList: mockTemplate, format: .xml, options: 0) |
| mockFileManager.mockContent[resourceURLs.stubIOSAppExInfoPlistTemplate.path] = templateData |
| |
| mockExtractor.labelToRuleEntry = ruleEntries |
| |
| generator = XcodeProjectGenerator( |
| workspaceRootURL: workspaceRoot, |
| config: config, |
| localizedMessageLogger: mockLocalizedMessageLogger, |
| workspaceInfoExtractor: mockExtractor, |
| resourceURLs: resourceURLs, |
| tulsiVersion: testTulsiVersion, |
| fileManager: mockFileManager, |
| pbxTargetGeneratorType: MockPBXTargetGenerator.self) |
| generator.redactWorkspaceSymlink = true |
| generator.suppressModifyingUserDefaults = true |
| generator.suppressGeneratingBuildSettings = true |
| generator.writeDataHandler = { (url, _) in |
| self.writtenFiles.insert(url.path) |
| } |
| generator.usernameFetcher = { "USER" } |
| } |
| } |
| |
| class MockFileManager: FileManager { |
| var filesThatExist = Set<String>() |
| var allowedDirectoryCreates = Set<String>() |
| var directoryOperations = [String]() |
| var copyOperations = [String: String]() |
| var writeOperations = [String: Data]() |
| var removeOperations = [String]() |
| var mockContent = [String: Data]() |
| var attributesMap = [String: [FileAttributeKey: Any]]() |
| |
| override open var homeDirectoryForCurrentUser: URL { |
| return URL(fileURLWithPath: "/Users/__MOCK_USER__", isDirectory: true) |
| } |
| |
| override func fileExists(atPath path: String) -> Bool { |
| return filesThatExist.contains(path) |
| } |
| |
| override func createDirectory( |
| at url: URL, |
| withIntermediateDirectories createIntermediates: Bool, |
| attributes: [FileAttributeKey: Any]? |
| ) throws { |
| guard !allowedDirectoryCreates.contains(url.path) else { |
| directoryOperations.append(url.path) |
| if let attributes = attributes { |
| self.setAttributes(attributes, path: url.path) |
| } |
| return |
| } |
| throw NSError( |
| domain: "MockFileManager: Directory creation disallowed", |
| code: 0, |
| userInfo: nil) |
| } |
| |
| override func createDirectory( |
| atPath path: String, |
| withIntermediateDirectories createIntermediates: Bool, |
| attributes: [FileAttributeKey: Any]? |
| ) throws { |
| guard !allowedDirectoryCreates.contains(path) else { |
| directoryOperations.append(path) |
| if let attributes = attributes { |
| self.setAttributes(attributes, path: path) |
| } |
| return |
| } |
| throw NSError( |
| domain: "MockFileManager: Directory creation disallowed", |
| code: 0, |
| userInfo: nil) |
| } |
| |
| override func removeItem(at URL: URL) throws { |
| removeOperations.append(URL.path) |
| } |
| |
| override func removeItem(atPath path: String) throws { |
| removeOperations.append(path) |
| } |
| |
| override func copyItem(at srcURL: URL, to dstURL: URL) throws { |
| copyOperations[dstURL.path] = srcURL.path |
| } |
| |
| override func copyItem(atPath srcPath: String, toPath dstPath: String) throws { |
| copyOperations[dstPath] = srcPath |
| } |
| |
| override func contents(atPath path: String) -> Data? { |
| return mockContent[path] |
| } |
| |
| override func createFile( |
| atPath path: String, contents data: Data?, attributes attr: [FileAttributeKey: Any]? = nil |
| ) -> Bool { |
| if writeOperations.keys.contains(path) { |
| fatalError("Attempting to overwrite an existing file at \(path)") |
| } |
| writeOperations[path] = data |
| if let attr = attr { |
| self.setAttributes(attr, path: path) |
| } |
| return true |
| } |
| |
| fileprivate func setAttributes(_ attributes: [FileAttributeKey: Any], path: String) { |
| var currentAttributes = attributesMap[path] ?? [FileAttributeKey: Any]() |
| attributes.forEach { (k, v) in |
| currentAttributes[k] = v |
| } |
| attributesMap[path] = currentAttributes |
| } |
| |
| override func setAttributes(_ attributes: [FileAttributeKey: Any], ofItemAtPath path: String) |
| throws |
| { |
| self.setAttributes(attributes, path: path) |
| } |
| } |
| |
| final class MockPBXTargetGenerator: PBXTargetGeneratorProtocol { |
| var project: PBXProject |
| |
| static func getRunTestTargetBuildConfigPrefix() -> String { |
| return "TestRunner__" |
| } |
| |
| static func workingDirectoryForPBXGroup(_ group: PBXGroup) -> String { |
| return "" |
| } |
| |
| static func mainGroupForOutputFolder(_ outputFolderURL: URL, workspaceRootURL: URL) -> PBXGroup { |
| return PBXGroup( |
| name: "mainGroup", |
| path: "/A/Test/Path", |
| sourceTree: .Absolute, |
| parent: nil) |
| } |
| |
| required init( |
| bazelPath: String, |
| bazelBinPath: String, |
| project: PBXProject, |
| buildScriptPath: String, |
| stubInfoPlistPaths: StubInfoPlistPaths, |
| tulsiVersion: String, |
| options: TulsiOptionSet, |
| localizedMessageLogger: LocalizedMessageLogger, |
| workspaceRootURL: URL, |
| suppressCompilerDefines: Bool, |
| redactWorkspaceSymlink: Bool |
| ) { |
| self.project = project |
| } |
| |
| func generateFileReferencesForFilePaths(_ paths: [String], pathFilters: Set<String>?) { |
| } |
| |
| func registerRuleEntryForIndexer( |
| _ ruleEntry: RuleEntry, |
| ruleEntryMap: RuleEntryMap, |
| pathFilters: Set<String>, |
| processedEntries: inout [RuleEntry: (NSOrderedSet)] |
| ) { |
| } |
| |
| func generateIndexerTargets() -> [String: PBXTarget] { |
| return [:] |
| } |
| |
| func generateBazelCleanTarget( |
| _ scriptPath: String, workingDirectory: String, |
| startupOptions: [String] |
| ) { |
| } |
| |
| func generateTopLevelBuildConfigurations(_ buildSettingOverrides: [String: String]) { |
| } |
| |
| func generateBuildTargetsForRuleEntries( |
| _ ruleEntries: Set<RuleEntry>, |
| ruleEntryMap: RuleEntryMap |
| ) throws -> [BuildLabel: PBXNativeTarget] { |
| // This works as this file only tests native targets that don't have multiple configurations. |
| let namedRuleEntries = ruleEntries.map { (e: RuleEntry) -> (String, RuleEntry) in |
| return (e.label.asFullPBXTargetName!, e) |
| } |
| |
| var targetsByLabel = [BuildLabel: PBXNativeTarget]() |
| var testTargetLinkages = [(PBXTarget, BuildLabel)]() |
| for (name, entry) in namedRuleEntries { |
| let target = project.createNativeTarget( |
| name, |
| deploymentTarget: entry.deploymentTarget, |
| targetType: entry.pbxTargetType!) |
| targetsByLabel[entry.label] = target |
| |
| |
| if let hostLabelString = entry.attributes[.test_host] as? String { |
| let hostLabel = BuildLabel(hostLabelString) |
| testTargetLinkages.append((target, hostLabel)) |
| } |
| } |
| |
| for (testTarget, testHostLabel) in testTargetLinkages { |
| let hostTarget = project.targetByName(testHostLabel.asFullPBXTargetName!) as! PBXNativeTarget |
| project.linkTestTarget(testTarget, toHostTarget: hostTarget) |
| } |
| return targetsByLabel |
| } |
| } |