|
| 1 | +:orphan: |
| 2 | + |
| 3 | +.. @raise litre.TestsAreMissing |
| 4 | +
|
| 5 | +============= |
| 6 | +Testing Swift |
| 7 | +============= |
| 8 | + |
| 9 | +This document describes how we test the Swift compiler, the Swift runtime, and |
| 10 | +the Swift standard library. |
| 11 | + |
| 12 | +Testing approaches |
| 13 | +================== |
| 14 | + |
| 15 | +We use multiple approaches to test the Swift toolchain. |
| 16 | + |
| 17 | +* LLVM lit-based testsuites for the compiler, runtime and the standard library. |
| 18 | + |
| 19 | +* A selection of open source projects written in Swift. |
| 20 | + |
| 21 | +The LLVM lit-based testsuite |
| 22 | +============================ |
| 23 | + |
| 24 | +**Purpose**: primary testsuites for the Swift toolchain. |
| 25 | + |
| 26 | +**Contents**: Functional and regression tests for all toolchain components. |
| 27 | + |
| 28 | +**Run by**: |
| 29 | + |
| 30 | +* Engineers and contributors are expected to run tests from these testsuites |
| 31 | + locally before commiting. (Usually on a single platform, and not necessarily |
| 32 | + all tests.) |
| 33 | + |
| 34 | +* Buildbots run all tests, on all supported platforms. |
| 35 | + |
| 36 | +Running the LLVM lit-based testsuite |
| 37 | +------------------------------------ |
| 38 | + |
| 39 | +You can run Swift tests using the ``build-script``, or, alternatively, using |
| 40 | +these targets in the build directory: |
| 41 | + |
| 42 | +* ``check-swift`` |
| 43 | + |
| 44 | + Runs tests from the ``${SWIFT_SOURCE_ROOT}/test`` directory. |
| 45 | + |
| 46 | +* ``check-swift-validation`` |
| 47 | + |
| 48 | + Runs tests from the ``${SWIFT_SOURCE_ROOT}/validation-test`` directory. |
| 49 | + |
| 50 | +* ``check-swift-all`` |
| 51 | + |
| 52 | + Runs all tests. |
| 53 | + |
| 54 | +For day-to-day work on the Swift compiler, using check-swift should be |
| 55 | +sufficient. The buildbot runs validation tests, so if those are accidentally |
| 56 | +broken, it should not go unnoticed. |
| 57 | + |
| 58 | +Before commiting a large change to a compiler (especially a language change), |
| 59 | +or API changes to the standard library, it is recommended to run validation |
| 60 | +test suite. |
| 61 | + |
| 62 | +For every target above, there are variants for different optimizations: |
| 63 | + |
| 64 | +* the target itself (e.g., ``check-swift``) -- runs execution tests in |
| 65 | + ``-Onone`` mode; |
| 66 | + |
| 67 | +* the target with ``-optimize`` suffix (e.g., ``check-swift-optimize``) -- runs |
| 68 | + execution tests in ``-O`` mode; This target will only run tests marked as |
| 69 | + ``executable_test``. |
| 70 | + |
| 71 | +* the target with ``-optimize-unchecked`` suffix (e.g., |
| 72 | + ``check-swift-optimize-unchecked``) -- runs execution tests in |
| 73 | + ``-Ounchecked`` mode. This target will only run tests marked as |
| 74 | + ``executable_test``. |
| 75 | + |
| 76 | +If you need to manually run certain tests, you can invoke LLVM's lit.py script |
| 77 | +directly. For example:: |
| 78 | + |
| 79 | + % ${LLVM_SOURCE_ROOT}/utils/lit/lit.py -sv ${SWIFT_BUILD_ROOT}/test-iphonesimulator-i386/Parse/ |
| 80 | + |
| 81 | +This runs the tests in the test/Parse/ directory targeting the 32-bit iOS |
| 82 | +Simulator. The ``-sv`` options give you a nice progress bar and only show you |
| 83 | +output from the tests that fail. |
| 84 | + |
| 85 | +One downside of using this form is that you're appending relative paths from |
| 86 | +the source directory to the test directory in your build directory. (That is, |
| 87 | +there may not actually be a directory named 'Parse' in |
| 88 | +'test-iphonesimulator-i386/'; the invocation works because there is one in the |
| 89 | +source 'test/' directory.) There is a more verbose form that specifies the |
| 90 | +testing configuration explicitly, which then allows you to test files |
| 91 | +regardless of location. |
| 92 | + |
| 93 | +:: |
| 94 | + |
| 95 | + % ${LLVM_SOURCE_ROOT}/utils/lit/lit.py -sv --param swift_site_config=${SWIFT_BUILD_ROOT}/test-iphonesimulator-i386/lit.site.cfg ${SWIFT_SOURCE_ROOT}/test/Parse/ |
| 96 | + |
| 97 | +For more complicated configuration, copy the invocation from one of the build |
| 98 | +targets mentioned above and modify it as necessary. lit.py also has several |
| 99 | +useful features, like timing tests and providing a timeout. Check these features |
| 100 | +out with ``lit.py -h``. |
| 101 | + |
| 102 | +Writing tests |
| 103 | +------------- |
| 104 | + |
| 105 | +General guidelines |
| 106 | +^^^^^^^^^^^^^^^^^^ |
| 107 | + |
| 108 | +When adding a new testcase, try to find an existing test file focused on the |
| 109 | +same topic rather than starting a new test file. There is a fixed runtime cost |
| 110 | +for every test file. On the other hand, avoid dumping new tests in a file that |
| 111 | +is only remotely related to the purpose of the new tests. |
| 112 | + |
| 113 | +Don't limit a test to a certain platform or hardware configuration just because |
| 114 | +this makes the test slightly easier to write. This sometimes means a little |
| 115 | +bit more work when adding the test, but the payoff from the increased testing |
| 116 | +is significant. We heavily rely on portable tests to port Swift to other |
| 117 | +platforms. |
| 118 | + |
| 119 | +Avoid using unstable language features in tests which test something else (for |
| 120 | +example, avoid using an unstable underscored attribute when another |
| 121 | +non-underscored attribute would work). |
| 122 | + |
| 123 | +Avoid using arbitrary implementation details of the standard library. Always |
| 124 | +prefer to define types locally in the test, if feasible. |
| 125 | + |
| 126 | +Avoid purposefully shadowing names from the standard library, this makes the |
| 127 | +test extremely confusing (if nothing else, to understand the intent --- was the |
| 128 | +compiler bug triggered by this shadowing?) When reducing a compiler testcase |
| 129 | +from the standard library source, rename the types and APIs in the testcase to |
| 130 | +differ from the standard library APIs. |
| 131 | + |
| 132 | +In IRGen, SILGen and SIL tests, avoid using platform-dependent implementation |
| 133 | +details of the standard library (unless doing so is point of the test). |
| 134 | +Platform-dependent details include: |
| 135 | + |
| 136 | +* ``Int`` (use integer types with explicit types instead). |
| 137 | + |
| 138 | +* Layout of ``String``, ``Array``, ``Dictionary``, ``Set``. These differ |
| 139 | + between platforms that have Objective-C interop and those that don't. |
| 140 | + |
| 141 | +Unless testing the standard library, avoid using arbitrary standard library |
| 142 | +types and APIs, even if it is very convenient for you to do so in your tests. |
| 143 | +Using the more common APIs like ``Array`` subscript or ``+`` on ``IntXX`` is |
| 144 | +acceptable. This is important because you can't rely on the full standard |
| 145 | +library being available. The long-term plan is to introduce a mock, minimal |
| 146 | +standard library that only has a very basic set of APIs. |
| 147 | + |
| 148 | +If you write an executable test please add ``REQUIRES: executable_test`` to the |
| 149 | +test. |
| 150 | + |
| 151 | +Substitutions in lit tests |
| 152 | +^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 153 | + |
| 154 | +Substitutions that start with ``%target`` configure the compiler for building |
| 155 | +code for the target that is not the build machine: |
| 156 | + |
| 157 | +* ``%target-parse-verify-swift``: parse and type check the current Swift file |
| 158 | + for the target platform and verify diagnostics, like ``swift -parse -verify |
| 159 | + %s``. |
| 160 | + |
| 161 | + Use this substitution for testing semantic analysis in the compiler. |
| 162 | + |
| 163 | +* ``%target-swift-frontend``: run ``swift -frontend`` for the target. |
| 164 | + |
| 165 | + Use this substitution (with extra arguments) for tests that don't fit any |
| 166 | + other pattern. |
| 167 | + |
| 168 | +* ``%target-swift-frontend(mock-sdk:`` *mock sdk arguments* ``)`` *other |
| 169 | + arguments*: like ``%target-swift-frontend``, but allows to specify command |
| 170 | + line parameters (typically ``-sdk`` and ``-I``) to use a mock SDK and SDK |
| 171 | + overlay that would take precedence over the target SDK. |
| 172 | + |
| 173 | +* ``%target-build-swift``: compile and link a Swift program for the target. |
| 174 | + |
| 175 | + Use this substitution only when you intend to run the program later in the |
| 176 | + test. |
| 177 | + |
| 178 | +* ``%target-run-simple-swift``: build a one-file Swift program and run it on |
| 179 | + the target machine. |
| 180 | + |
| 181 | + Use this substitution for executable tests that don't require special |
| 182 | + compiler arguments. |
| 183 | + |
| 184 | + Add ``REQUIRES: executable_test`` to the test. |
| 185 | + |
| 186 | +* ``%target-run-stdlib-swift``: like ``%target-run-simple-swift`` with |
| 187 | + ``-parse-stdlib -Xfrontend -disable-access-control``. |
| 188 | + |
| 189 | + This is sometimes useful for testing the Swift standard library. |
| 190 | + |
| 191 | + Add ``REQUIRES: executable_test`` to the test. |
| 192 | + |
| 193 | +* ``%target-repl-run-simple-swift``: run a Swift program in a REPL on the |
| 194 | + target machine. |
| 195 | + |
| 196 | +* ``%target-run``: run a command on the target machine. |
| 197 | + |
| 198 | + Add ``REQUIRES: executable_test`` to the test. |
| 199 | + |
| 200 | +* ``%target-jit-run``: run a Swift program on the target machine using a JIT |
| 201 | + compiler. |
| 202 | + |
| 203 | +* ``%target-swiftc_driver``: FIXME |
| 204 | + |
| 205 | +* ``%target-sil-opt``: run ``sil-opt`` for the target. |
| 206 | + |
| 207 | +* ``%target-sil-extract``: run ``sil-extract`` for the target. |
| 208 | + |
| 209 | +* ``%target-swift-ide-test``: run ``swift-ide-test`` for the target. |
| 210 | + |
| 211 | +* ``%target-swift-ide-test(mock-sdk:`` *mock sdk arguments* ``)`` *other |
| 212 | + arguments*: like ``%target-swift-ide-test``, but allows to specify command |
| 213 | + line parameters to use a mock SDK. |
| 214 | + |
| 215 | +* ``%target-swiftc_driver``: FIXME. |
| 216 | + |
| 217 | +* ``%target-swift-autolink-extract``: run ``swift-autolink-extract`` for the |
| 218 | + target to extract its autolink flags on platforms that support them (when the |
| 219 | + autolink-extract feature flag is set) |
| 220 | + |
| 221 | +* ``%target-clang``: run the system's ``clang++`` for the target. |
| 222 | + |
| 223 | + If you want to run the ``clang`` executable that was built alongside |
| 224 | + Swift, use ``%clang`` instead. |
| 225 | + |
| 226 | +* ``%target-ld``: run ``ld`` configured with flags pointing to the standard |
| 227 | + library directory for the target. |
| 228 | + |
| 229 | +* ``%target-cc-options``: the clang flags to setup the target with the right |
| 230 | + architecture and platform version. |
| 231 | + |
| 232 | +Always use ``%target-*`` substitutions unless you have a good reason. For |
| 233 | +example, an exception would be a test that checks how the compiler handles |
| 234 | +mixing module files for incompatible platforms (that test would need to compile |
| 235 | +Swift code for two different platforms that are known to be incompatible). |
| 236 | + |
| 237 | +When you can't use ``%target-*`` substitutions, you can use: |
| 238 | + |
| 239 | +* ``%swift_driver_plain``: FIXME. |
| 240 | +* ``%swiftc_driver_plain``: FIXME. |
| 241 | +* ``%swift_driver``: FIXME. |
| 242 | +* ``%swiftc_driver``: FIXME. |
| 243 | +* ``%sil-opt``: FIXME. |
| 244 | +* ``%sil-extract``: FIXME. |
| 245 | +* ``%lldb-moduleimport-test``: FIXME. |
| 246 | +* ``%swift-ide-test_plain``: FIXME. |
| 247 | +* ``%swift-ide-test``: FIXME. |
| 248 | +* ``%llvm-opt``: FIXME. |
| 249 | +* ``%swift``: FIXME. |
| 250 | +* ``%clang-include-dir``: FIXME. |
| 251 | +* ``%clang-importer-sdk``: FIXME. |
| 252 | + |
| 253 | +Other substitutions: |
| 254 | + |
| 255 | +* ``%leaks-runner``: FIXME. |
| 256 | +* ``%clang_apinotes``: FIXME. |
| 257 | +* ``%clang``: FIXME. |
| 258 | +* ``%target-triple``: FIXME, possible values. |
| 259 | +* ``%target-cpu``: FIXME, possible values. |
| 260 | +* ``%target-os``: FIXME, possible values. |
| 261 | +* ``%target-object-format``: the platform's object format (elf, macho, coff). |
| 262 | +* ``%target-runtime``: the platform's Swift runtime (objc, native). |
| 263 | +* ``%target-ptrsize``: the pointer size of the target (32, 64). |
| 264 | +* ``%sdk``: FIXME. |
| 265 | +* ``%gyb``: FIXME. |
| 266 | + |
| 267 | +* ``%platform-module-dir``: absolute path of the directory where the stdandard |
| 268 | + library module file for the target platform is stored. For example, |
| 269 | + ``/.../lib/swift/macosx``. |
| 270 | + |
| 271 | +* ``%platform-sdk-overlay-dir``: absolute path of the directory where the SDK |
| 272 | + overlay module files for the target platform are stored. |
| 273 | + |
| 274 | +* ``%target-swiftmodule-name`` and ``%target-swiftdoc-name``: the basename of |
| 275 | + swiftmodule and swiftdoc files for a framework compiled for the target (for |
| 276 | + example, ``arm64.swiftmodule`` and ``arm64.swiftdoc``). |
| 277 | + |
| 278 | +* ``%target-sdk-name``: only for Apple platforms: ``xcrun``-style SDK name |
| 279 | + (``macosx``, ``iphoneos``, ``iphonesimulator``). |
| 280 | + |
| 281 | +When writing a test where output (or IR, SIL) depends on the bitness of the |
| 282 | +target CPU, use this pattern:: |
| 283 | + |
| 284 | + // RUN: %target-swift-frontend ... | FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize %s |
| 285 | + |
| 286 | + // CHECK: common line |
| 287 | + // CHECK-32: only for 32-bit |
| 288 | + // CHECK-64: only for 64-bit |
| 289 | + |
| 290 | + // FileCheck does a single pass for a combined set of CHECK lines, so you can |
| 291 | + // do this: |
| 292 | + // |
| 293 | + // CHECK: define @foo() { |
| 294 | + // CHECK-32: integer_literal $Builtin.Int32, 0 |
| 295 | + // CHECK-64: integer_literal $Builtin.Int64, 0 |
| 296 | + |
| 297 | +When writing a test where output (or IR, SIL) depends on the target CPU itself, |
| 298 | +use this pattern:: |
| 299 | + |
| 300 | + // RUN: %target-swift-frontend ... | FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-cpu %s |
| 301 | + |
| 302 | + // CHECK: common line |
| 303 | + // CHECK-i386: only for i386 |
| 304 | + // CHECK-x86_64: only for x86_64 |
| 305 | + // CHECK-armv7: only for armv7 |
| 306 | + // CHECK-arm64: only for arm64 |
| 307 | + |
| 308 | +Features for ``REQUIRES`` and ``XFAIL`` |
| 309 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 310 | + |
| 311 | +FIXME: list. |
| 312 | + |
| 313 | +When writing a test specific to x86, if possible, prefer ``REQUIRES: |
| 314 | +CPU=i386_or_x86_64`` to ``REQUIRES: CPU=x86_64``. |
| 315 | + |
| 316 | +``swift_test_mode_optimize[_unchecked|none]`` and |
| 317 | +``swift_test_mode_optimize[_unchecked|none]_<CPUNAME>`` to specify a test mode |
| 318 | +plus cpu configuration. |
| 319 | + |
| 320 | +``optimized_stdlib_<CPUNAME>``` to specify a optimized stdlib plus cpu |
| 321 | +configuration. |
| 322 | + |
| 323 | +Feature ``REQUIRES: executable_test`` |
| 324 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 325 | + |
| 326 | +This feature marks an executable test. The test harness makes this feature |
| 327 | +generally available. It can be used to restrict the set of tests to run. |
| 328 | + |
| 329 | +StdlibUnittest |
| 330 | +^^^^^^^^^^^^^^ |
| 331 | + |
| 332 | +Tests accept command line parameters, run StdlibUnittest-based test binary |
| 333 | +with ``--help`` for more information. |
| 334 | + |
| 335 | +Testing memory management in execution tests |
| 336 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 337 | + |
| 338 | +In execution tests, memory management testing should be performed |
| 339 | +using local variables enclosed in a closure passed to the standard |
| 340 | +library ``autoreleasepool`` function. For example:: |
| 341 | + |
| 342 | + // A counter that's decremented by Canary's deinitializer. |
| 343 | + var CanaryCount = 0 |
| 344 | + |
| 345 | + // A class whose instances increase a counter when they're destroyed. |
| 346 | + class Canary { |
| 347 | + deinit { ++CanaryCount } |
| 348 | + } |
| 349 | + |
| 350 | + // Test that a local variable is correctly released before it goes out of |
| 351 | + // scope. |
| 352 | + CanaryCount = 0 |
| 353 | + autoreleasepool { |
| 354 | + let canary = Canary() |
| 355 | + } |
| 356 | + assert(CanaryCount == 1, "canary was not released") |
| 357 | + |
| 358 | +Memory management tests should be performed in a local scope because Swift does |
| 359 | +not guarantee the destruction of global variables. Code that needs to |
| 360 | +interoperate with Objective-C may put references in the autorelease pool, so |
| 361 | +code that uses an ``if true {}`` or similar no-op scope instead of |
| 362 | +``autoreleasepool`` may falsely report leaks or fail to catch overrelease bugs. |
| 363 | +If you're specifically testing the autoreleasing behavior of code, or do not |
| 364 | +expect code to interact with the Objective-C runtime, it may be OK to use ``if |
| 365 | +true {}``, but those assumptions should be commented in the test. |
0 commit comments