Skip to content

Commit ae3d2cf

Browse files
committed
Store test content in a custom metadata section.
See also: swiftlang/swift#76698 Resolves #735.
1 parent b439448 commit ae3d2cf

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

Documentation/ABI/TestContent.md

+42-22
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,38 @@ the testing library are stored in dedicated platform-specific sections:
2121

2222
| Platform | Binary Format | Section Name |
2323
|-|:-:|-|
24-
| macOS | Mach-O | `__DATA_CONST,__swift5_tests` |
25-
| iOS | Mach-O | `__DATA_CONST,__swift5_tests` |
26-
| watchOS | Mach-O | `__DATA_CONST,__swift5_tests` |
27-
| tvOS | Mach-O | `__DATA_CONST,__swift5_tests` |
28-
| visionOS | Mach-O | `__DATA_CONST,__swift5_tests` |
29-
| Linux | ELF | `PT_NOTE`[^1] |
30-
| FreeBSD | ELF | `PT_NOTE`[^1] |
31-
| Android | ELF | `PT_NOTE`[^1] |
24+
| macOS, iOS, watchOS, tvOS, visionOS | Mach-O | `__DATA_CONST,__swift5_tests` |
25+
| Linux, FreeBSD, Android | ELF | `PT_NOTE`[^1] |
3226
| WASI | Statically Linked | `swift5_tests` |
3327
| Windows | PE/COFF | `.sw5test` |
3428

3529
[^1]: On platforms that use the ELF binary format natively, test content records
3630
are stored in ELF program headers of type `PT_NOTE`. Take care not to
3731
remove these program headers (for example, by invoking [`strip(1)`](https://www.man7.org/linux/man-pages/man1/strip.1.html).)
3832

39-
### Determining the type of test content
33+
### Record headers
4034
4135
Regardless of platform, all test content records created and discoverable by the
42-
testing library start have the name `"Swift Testing"` stored in the implied
43-
`n_name` field of their underlying ELF Notes. Each record's _type_ (stored in
44-
the underlying ELF Note's `n_type` field) determines how the record will be
45-
interpreted at runtime:
36+
testing library have the following structure:
37+
38+
```c
39+
struct SWTTestContentHeader {
40+
int32_t n_namesz;
41+
int32_t n_descsz;
42+
int32_t n_type;
43+
char n_name[n_namesz];
44+
// ...
45+
};
46+
47+
The size of `n_name` is dynamic and cannot be statically computed. The testing
48+
library always generates the name `"Swift Testing"` and specifies an `n_namesz`
49+
value of `20` (the string being null-padded to the correct length), but other
50+
content may be present in the same section whose header content differs. For
51+
more information about this structure such as its alignment requirements, see
52+
the documentation for the [ELF format](https://man7.org/linux/man-pages/man5/elf.5.html).
53+
54+
Each record's _kind_ (stored in the `n_type` field) determines how the record
55+
will be interpreted at runtime:
4656
4757
| Type Value | Interpretation |
4858
|-:|-|
@@ -54,18 +64,27 @@ interpreted at runtime:
5464
<!-- When adding cases to this enumeration, be sure to also update the
5565
corresponding enumeration in Discovery.h and TestContentGeneration.swift. -->
5666
57-
### Loading test content from a record
67+
### Record contents
5868
59-
For all currently-defined record types, the header and name are followed by a
60-
structure of the following form:
69+
For all currently-defined record types, the header structure is immediately
70+
followed by the actual content of the record. A test content record currently
71+
contains an `accessor` function to load the corresponding Swift content and a
72+
`flags` field whose value depends on the type of record. The overall structure
73+
of a record therefore looks like:
6174
6275
```c
6376
struct SWTTestContent {
77+
SWTTestContentHeader header;
6478
bool (* accessor)(void *);
6579
uint64_t flags;
6680
};
6781
```
6882
83+
This structure may grow in the future as needed. Check the `header.n_descsz`
84+
field to determine if there are additional fields present. Do not assume that
85+
the size of this structure will remain fixed over time or that all discovered
86+
test content records are the same size.
87+
6988
#### The accessor field
7089
7190
The function `accessor` is a C function whose signature in Swift can be restated
@@ -80,19 +99,20 @@ Swift type and returns `true`, or returns `false` if it could not generate the
8099
relevant content. On successful return, the caller is responsible for
81100
deinitializing the memory at `outValue` when done with it.
82101
83-
The concrete Swift type of `accessor`'s result depends on the type of record:
102+
The concrete Swift type of the value written to `outValue` depends on the type
103+
of record:
84104
85105
| Type Value | Return Type |
86106
|-:|-|
87107
| < `0` | Undefined (**do not use**) |
88-
| `0` ... `99` | `nil` |
108+
| `0` ... `99` | Reserved (**do not use**) |
89109
| `100` | `@Sendable () async -> Test`[^2] |
90-
| `101` | `ExitTest` (owned by caller) |
110+
| `101` | `ExitTest` (consumed by caller) |
91111
92112
[^2]: This signature is not the signature of `accessor`, but of the Swift
93-
function reference it returns. This level of indirection is necessary
94-
because loading a test or suite declaration is an asynchronous operation,
95-
but C functions cannot be `async`.
113+
function reference it writes to `outValue`. This level of indirection is
114+
necessary because loading a test or suite declaration is an asynchronous
115+
operation, but C functions cannot be `async`.
96116
97117
#### The flags field
98118

0 commit comments

Comments
 (0)