blob: 9e374746a8ecd61f6522d41cf9b3c4bced5832b1 [file] [log] [blame]
// 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 BazelIntegrationTestCase
@testable import EndToEndIntegrationTestCase
@testable import TulsiGenerator
// End to end tests that generate xcodeproj bundles and validate them against golden versions.
class EndToEndGenerationTests: EndToEndIntegrationTestCase {
func test_SimpleProject() throws {
let testDir = "tulsi_e2e_simple"
installBUILDFile("Simple", intoSubdirectory: testDir)
makeTestXCDataModel("SimpleDataModelsTestv1",
inSubdirectory: "\(testDir)/SimpleTest.xcdatamodeld")
makeTestXCDataModel("SimpleDataModelsTestv2",
inSubdirectory: "\(testDir)/SimpleTest.xcdatamodeld")
makePlistFileNamed(".xccurrentversion",
withContent: ["_XCCurrentVersionName": "SimpleDataModelsTestv1.xcdatamodel"],
inSubdirectory: "\(testDir)/SimpleTest.xcdatamodeld")
let appLabel = BuildLabel("//\(testDir):Application")
let targetLabel = BuildLabel("//\(testDir):TargetApplication")
let hostLabels = Set<BuildLabel>([appLabel])
let buildTargets = [RuleInfo(label: appLabel,
type: "ios_application",
linkedTargetLabels: []),
RuleInfo(label: targetLabel,
type: "ios_application",
linkedTargetLabels: []),
RuleInfo(label: BuildLabel("//\(testDir):XCTest"),
type: "apple_unit_test",
linkedTargetLabels: hostLabels)]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "SimpleProject"
let options = TulsiOptionSet()
options.options[.BazelContinueBuildingAfterError]?.projectValue = "YES"
options.options[.CommandlineArguments]?.projectValue = "--project-flag"
options.options[.CommandlineArguments]?.targetValues?[targetLabel.value] = "--target-specific-test-flag"
options.options[.EnvironmentVariables]?.projectValue = "projectKey=projectValue"
options.options[.EnvironmentVariables]?.targetValues?[targetLabel.value] =
"targetKey1=targetValue1\ntargetKey2=targetValue2=\ntargetKey3="
options.options[.BuildActionPreActionScript]?.projectValue = "This is a build pre action script"
options.options[.BuildActionPreActionScript]?.targetValues?[targetLabel.value] = "This is a target specific build pre action script"
options.options[.BuildActionPostActionScript]?.projectValue = "This is a build post action script"
options.options[.BuildActionPostActionScript]?.targetValues?[targetLabel.value] = "This is a target specific build post action script"
options.options[.LaunchActionPreActionScript]?.projectValue = "This is a lauch pre action script"
options.options[.LaunchActionPreActionScript]?.targetValues?[targetLabel.value] = "This is a target specific launch pre action script"
options.options[.LaunchActionPostActionScript]?.projectValue = "This is a launch post action script"
options.options[.LaunchActionPostActionScript]?.targetValues?[targetLabel.value] = "This is a target specific launch post action script"
options.options[.TestActionPreActionScript]?.projectValue = "This is a test pre action script"
options.options[.TestActionPreActionScript]?.targetValues?[targetLabel.value] = "This is a target specific test pre action script"
options.options[.TestActionPostActionScript]?.projectValue = "This is a test post action script"
options.options[.TestActionPostActionScript]?.targetValues?[targetLabel.value] = "This is a target specific test post action script"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output",
options: options)
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_MultiExtensionProject() throws {
let testDir = "tulsi_e2e_multi_extension"
installBUILDFile("MultiExtension", intoSubdirectory: testDir)
let appLabelOne = BuildLabel("//\(testDir):ApplicationOne")
let appLabelTwo = BuildLabel("//\(testDir):ApplicationTwo")
let buildTargets = [RuleInfo(label: appLabelOne,
type: "ios_application",
linkedTargetLabels: []),
RuleInfo(label: appLabelTwo,
type: "ios_application",
linkedTargetLabels: [])]
let additionalFilePaths = ["\(testDir)/BUILD"]
makePlistFileNamed("Plist1.plist",
withContent: ["NSExtension": ["NSExtensionPointIdentifier": "com.apple.extension-foo"],
"CFBundleVersion": "1.0",
"CFBundleShortVersionString": "1.0"],
inSubdirectory: "\(testDir)/TodayExtension")
let projectName = "MultiExtensionProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_BrokenSourceBUILD() {
let aspectLogExpectation = expectation(description:
"Should see a statement that Bazel aspect info is being printed to our logs."
)
let observerName = NSNotification.Name(rawValue: TulsiMessageNotification)
let observer = NotificationCenter.default.addObserver(forName: observerName,
object: nil,
queue: nil) {
notification in
guard let item = LogMessage(notification: notification),
item.message == "Log of Bazel aspect info output follows:" &&
item.level == .Info else {
return
}
aspectLogExpectation.fulfill()
}
defer { NotificationCenter.default.removeObserver(observer) }
let testDir = "tulsi_e2e_broken_build"
installBUILDFile("SimpleBad", intoSubdirectory: testDir)
let appLabel = BuildLabel("//\(testDir):Application")
let buildTargets = [RuleInfo(label: appLabel,
type: "ios_application",
linkedTargetLabels: [])]
do {
_ = try generateProjectNamed("BrokenSourceBuildProject",
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
outputDir: "tulsi_e2e_output")
} catch Error.projectGenerationFailure(let info) {
// Expected failure on malformed BUILD file.
XCTAssertEqual(info, "General failure: Bazel aspects could not be built.")
waitForExpectations(timeout: 0.0, handler: nil)
return
} catch Error.testSubdirectoryNotCreated {
XCTFail("Failed to create output folder, aborting test.")
} catch Error.userBuildScriptInvocationFailure(let info) {
XCTFail("Failed to invoke user_build.py script. Context: \(info)")
} catch let error {
XCTFail("Unexpected failure: \(error)")
}
XCTFail("Expected exception of type 'BazelAspectInfoExtractor.ExtractorError.buildFailed' " +
"to be thrown for bazel aspect build error.")
}
func test_ComplexSingleProject() throws {
let testDir = "tulsi_e2e_complex"
installBUILDFile("ComplexSingle", intoSubdirectory: testDir)
makeTestXCDataModel("DataModelsTestv1", inSubdirectory: "\(testDir)/Test.xcdatamodeld")
makeTestXCDataModel("DataModelsTestv2", inSubdirectory: "\(testDir)/Test.xcdatamodeld")
makePlistFileNamed(".xccurrentversion",
withContent: ["_XCCurrentVersionName": "DataModelsTestv2.xcdatamodel"],
inSubdirectory: "\(testDir)/Test.xcdatamodeld")
// iOS extension's Info.plist is generated by the Aspect after reading the infoplists listed in
// the attribute, so we'll need to generate them otherwise extraction will fail.
makePlistFileNamed("Plist1.plist",
withContent: ["NSExtension": ["NSExtensionPointIdentifier": "com.apple.extension-foo"],
"CFBundleVersion": "1.0",
"CFBundleShortVersionString": "1.0"],
inSubdirectory: "\(testDir)/TodayExtension")
let appLabel = BuildLabel("//\(testDir):Application")
let hostLabels = Set<BuildLabel>([appLabel])
let buildTargets = [RuleInfo(label: appLabel,
type: "ios_application",
linkedTargetLabels: []),
RuleInfo(label: BuildLabel("//\(testDir):XCTest"),
type: "apple_unit_test",
linkedTargetLabels: hostLabels)]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "ComplexSingleProject"
let projectOptions = TulsiOptionSet()
projectOptions[.IncludeBuildSources].projectValue = "YES"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output",
options: projectOptions)
try validateBuildCommandForProject(projectURL, options: projectOptions, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_SwiftProject() throws {
let testDir = "tulsi_e2e_swift"
installBUILDFile("Swift", intoSubdirectory: testDir)
let appLabel = BuildLabel("//\(testDir):Application")
let buildTargets = [RuleInfo(label: appLabel,
type: "ios_application",
linkedTargetLabels: [])]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "SwiftProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
try validateBuildCommandForProject(projectURL, swift: true, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_watchProject() throws {
let testDir = "tulsi_e2e_watch"
installBUILDFile("Watch", intoSubdirectory: testDir)
let appLabel = BuildLabel("//\(testDir):Application")
let buildTargets = [RuleInfo(label: appLabel,
type: "ios_application",
linkedTargetLabels: [])]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "WatchProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
try validateBuildCommandForProject(projectURL, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_tvOSProject() throws {
let testDir = "tulsi_e2e_tvos_project"
installBUILDFile("ComplexSingle", intoSubdirectory: testDir)
let appLabel = BuildLabel("//\(testDir):tvOSApplication")
let buildTargets = [RuleInfo(label: appLabel,
type: "tvos_application",
linkedTargetLabels: [])
]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectURL = try generateProjectNamed("SkylarkBundlingProject",
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/\(testDir)/...",
"bazel-genfiles/\(testDir)/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
try validateBuildCommandForProject(projectURL, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: "SkylarkBundlingProject")
validateDiff(diffLines)
}
func test_macProject() throws {
let testDir = "tulsi_e2e_mac"
installBUILDFile("Mac", intoSubdirectory: testDir)
let appLabel = BuildLabel("//\(testDir):MyMacOSApp")
let commandLineAppLabel = BuildLabel("//\(testDir):MyCommandLineApp")
let buildTargets = [RuleInfo(label: appLabel,
type: "macos_application",
linkedTargetLabels: []),
RuleInfo(label: commandLineAppLabel,
type: "macos_command_line_application",
linkedTargetLabels: [])]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "MacOSProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
try validateBuildCommandForProject(projectURL, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_macTestsProject() throws {
let testDir = "tulsi_e2e_mac"
installBUILDFile("Mac", intoSubdirectory: testDir)
let appLabel = BuildLabel("//\(testDir):MyMacOSApp")
let unitTestsLabel = BuildLabel("//\(testDir):UnitTests")
let unitTestsNoHostLabel = BuildLabel("//\(testDir):UnitTestsNoHost")
let uiTestsLabel = BuildLabel("//\(testDir):UITests")
let hostLabels = Set<BuildLabel>([appLabel])
let buildTargets = [RuleInfo(label: unitTestsLabel,
type: "apple_unit_test",
linkedTargetLabels: hostLabels),
RuleInfo(label: unitTestsNoHostLabel,
type: "apple_unit_test",
linkedTargetLabels: []),
RuleInfo(label: uiTestsLabel,
type: "apple_ui_test",
linkedTargetLabels: hostLabels)]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "MacOSTestsProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/...",
"bazel-bin/...",
"bazel-genfiles/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
try validateBuildCommandForProject(projectURL, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_simpleCCProject() throws {
let testDir = "tulsi_e2e_ccsimple"
let appLabel = BuildLabel("//\(testDir):ccBinary")
installBUILDFile("Simple", intoSubdirectory: testDir)
let buildTargets = [RuleInfo(label: appLabel,
type: "cc_binary",
linkedTargetLabels: [])]
let additionalFilePaths = ["\(testDir)/BUILD"]
let projectName = "SimpleCCProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/..."],
additionalFilePaths: additionalFilePaths,
outputDir: "tulsi_e2e_output")
try validateBuildCommandForProject(projectURL, targets: [appLabel.value])
let diffLines = diffProjectAt(projectURL, againstGoldenProject: projectName)
validateDiff(diffLines)
}
}
// End to end tests that generate xcodeproj bundles and validate them against golden versions.
class TestSuiteEndToEndGenerationTests: EndToEndIntegrationTestCase {
let testDir = "TestSuite"
let appRule = RuleInfo(label: BuildLabel("//TestSuite:TestApplication"),
type: "ios_application",
linkedTargetLabels: [])
override func setUp() {
super.setUp()
installBUILDFile("TestSuiteRoot",
intoSubdirectory: testDir,
fromResourceDirectory: "TestSuite")
installBUILDFile("TestOne",
intoSubdirectory: "\(testDir)/One",
fromResourceDirectory: "TestSuite/One")
installBUILDFile("TestTwo",
intoSubdirectory: "\(testDir)/Two",
fromResourceDirectory: "TestSuite/Two")
installBUILDFile("TestThree",
intoSubdirectory: "\(testDir)/Three",
fromResourceDirectory: "TestSuite/Three")
}
func test_ExplicitXCTestsProject() throws {
let buildTargets = [
appRule,
RuleInfo(label: BuildLabel("//\(testDir):explicit_XCTests"),
type: "test_suite",
linkedTargetLabels: []),
]
let projectName = "TestSuiteExplicitXCTestsProject"
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/..."],
outputDir: "tulsi_e2e_output")
let diffLines = diffProjectAt(projectURL,
againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_TestSuiteLocalTaggedTestsProject() throws {
let buildTargets = [
appRule,
RuleInfo(label: BuildLabel("//\(testDir):local_tagged_tests"),
type: "test_suite",
linkedTargetLabels: []),
]
let projectName = "TestSuiteLocalTaggedTestsProject"
let options = TulsiOptionSet()
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/..."],
outputDir: "tulsi_e2e_output",
options: options)
let diffLines = diffProjectAt(projectURL,
againstGoldenProject: projectName)
validateDiff(diffLines)
}
func test_TestSuiteRecursiveTestSuiteProject() throws {
let buildTargets = [
appRule,
RuleInfo(label: BuildLabel("//\(testDir):recursive_test_suite"),
type: "test_suite",
linkedTargetLabels: []),
]
let projectName = "TestSuiteRecursiveTestSuiteProject"
let options = TulsiOptionSet()
let projectURL = try generateProjectNamed(projectName,
buildTargets: buildTargets,
pathFilters: ["\(testDir)/..."],
outputDir: "tulsi_e2e_output",
options: options)
let diffLines = diffProjectAt(projectURL,
againstGoldenProject: projectName)
validateDiff(diffLines)
}
}