File: XCTestMain.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (173 lines) | stat: -rw-r--r-- 6,407 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//
//  XCTestMain.swift
//  This is the main file for the framework. It provides the entry point function
//  for running tests and some infrastructure for running them.
//

// Note that we are re-exporting Foundation so tests importing XCTest don't need
// to import it themselves. This is consistent with the behavior of Apple XCTest
#if os(macOS)
    #if USE_FOUNDATION_FRAMEWORK
    @_exported import Foundation
    #else
    @_exported import SwiftFoundation
    #endif
#else
    @_exported import Foundation
#endif

#if canImport(Darwin)
    import Darwin
#elseif canImport(Glibc)
    import Glibc
#endif

/// Starts a test run for the specified test cases.
///
/// Example usage:
///
///     class TestFoo: XCTestCase {
///         static var allTests = {
///             return [
///                 ("test_foo", test_foo),
///                 ("test_bar", test_bar),
///             ]
///         }()
///
///         func test_foo() {
///             // Test things...
///         }
///
///         // etc...
///     }
///
///     let exitCode = XCTMain([ testCase(TestFoo.allTests) ])
///
/// Command line arguments can be used to select a particular test case or class
/// to execute. For example:
///
///     ./FooTests FooTestCase/testFoo  # Run a single test case
///     ./FooTests FooTestCase          # Run all the tests in FooTestCase
///
/// - Parameters:
///     - testCases: An array of test cases run, each produced by a call to the
///         `testCase` function.
///     - arguments: Command-line arguments to pass to XCTest. By default, the
///         arguments passed to the process are used.
///     - observers: Zero or more observers that should observe events that
///         occur while testing. If `nil` (the default), events are written to
///         the console.
///
/// - Returns: The exit code to use when the process terminates. `EXIT_SUCCESS`
///     indicates success, while any other value (including `EXIT_FAILURE`)
///     indicates failure.
@_disfavoredOverload
public func XCTMain(
    _ testCases: [XCTestCaseEntry],
    arguments: [String] = CommandLine.arguments,
    observers: [XCTestObservation]? = nil
) -> CInt {
    let observers = observers ?? [PrintObserver()]
    let testBundle = Bundle.main

    let executionMode = ArgumentParser(arguments: arguments).executionMode

    // Apple XCTest behaves differently if tests have been filtered:
    // - The root `XCTestSuite` is named "Selected tests" instead of
    //   "All tests".
    // - An `XCTestSuite` representing the .xctest test bundle is not included.
    let rootTestSuite: XCTestSuite
    let currentTestSuite: XCTestSuite
    if executionMode.selectedTestNames == nil {
        rootTestSuite = XCTestSuite(name: "All tests")
        currentTestSuite = XCTestSuite(name: "\(testBundle.bundleURL.lastPathComponent).xctest")
        rootTestSuite.addTest(currentTestSuite)
    } else {
        rootTestSuite = XCTestSuite(name: "Selected tests")
        currentTestSuite = rootTestSuite
    }

    let filter = TestFiltering(selectedTestNames: executionMode.selectedTestNames)
    TestFiltering.filterTests(testCases, filter: filter.selectedTestFilter)
        .map(XCTestCaseSuite.init)
        .forEach(currentTestSuite.addTest)

    switch executionMode {
    case .list(type: .humanReadable):
        TestListing(testSuite: rootTestSuite).printTestList()
        return EXIT_SUCCESS
    case .list(type: .json):
        TestListing(testSuite: rootTestSuite).printTestJSON()
        return EXIT_SUCCESS
    case let .help(invalidOption):
        if let invalid = invalidOption {
            let errMsg = "Error: Invalid option \"\(invalid)\"\n"
            FileHandle.standardError.write(errMsg.data(using: .utf8) ?? Data())
        }
        let exeName = URL(fileURLWithPath: arguments[0]).lastPathComponent
        let sampleTest = rootTestSuite.list().first ?? "Tests.FooTestCase/testFoo"
        let sampleTests = sampleTest.prefix(while: { $0 != "/" })
        print("""
              Usage: \(exeName) [OPTION]
                     \(exeName) [TESTCASE]
              Run and report results of test cases.

              With no OPTION or TESTCASE, runs all test cases.

              OPTIONS:

              -l, --list-test              List tests line by line to standard output
                  --dump-tests-json        List tests in JSON to standard output

              TESTCASES:

                 Run a single test

                     > \(exeName) \(sampleTest)

                 Run all the tests in \(sampleTests)

                     > \(exeName) \(sampleTests)
              """)
        return invalidOption == nil ? EXIT_SUCCESS : EXIT_FAILURE
    case .run(selectedTestNames: _):
        // Add a test observer that prints test progress to stdout.
        let observationCenter = XCTestObservationCenter.shared
        for observer in observers {
            observationCenter.addTestObserver(observer)
        }

        observationCenter.testBundleWillStart(testBundle)
        rootTestSuite.run()
        observationCenter.testBundleDidFinish(testBundle)

        return rootTestSuite.testRun!.totalFailureCount == 0 ? EXIT_SUCCESS : EXIT_FAILURE
    }
}

// @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.")
public func XCTMain(_ testCases: [XCTestCaseEntry]) -> Never {
    exit(XCTMain(testCases, arguments: CommandLine.arguments, observers: nil) as CInt)
}

// @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.")
public func XCTMain(_ testCases: [XCTestCaseEntry], arguments: [String]) -> Never {
    exit(XCTMain(testCases, arguments: arguments, observers: nil) as CInt)
}

// @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.")
public func XCTMain(
    _ testCases: [XCTestCaseEntry],
    arguments: [String],
    observers: [XCTestObservation]
) -> Never {
    exit(XCTMain(testCases, arguments: arguments, observers: observers) as CInt)
}